美文网首页
数据结构以及算法

数据结构以及算法

作者: Poppy11 | 来源:发表于2020-11-27 17:16 被阅读0次

    概念

    栈是一个线性结构,在计算机中是一个相当常见的数据结构。

    栈的特点是只能在某一端添加或删除数据,遵循先进后出的原则
    实现
    每种数据结构都可以用很多种方式来实现,其实可以把栈看成是数组的一个子集,所以这里使用数组来实现

    class Stack {
      constructor() {
        this.stack = []
      }
      push(item) {
        this.stack.push(item)
      }
      pop() {
        this.stack.pop()
      }
      peek() {
        return this.stack[this.getCount() - 1]
      }
      getCount() {
        return this.stack.length
      }
      isEmpty() {
        return this.getCount() === 0
      }
    }
    

    应用

    选取了 LeetCode 上序号为 20 的题目

    题意是匹配括号,可以通过栈的特性来完成这道题目

    var isValid = function (s) {
      let map = {
        '(': -1,
        ')': 1,
        '[': -2,
        ']': 2,
        '{': -3,
        '}': 3
      }
      let stack = []
      for (let i = 0; i < s.length; i++) {
        if (map[s[i]] < 0) {
          stack.push(s[i])
        } else {
          let last = stack.pop()
          if (map[last] + map[s[i]] != 0) return false
        }
      }
      if (stack.length > 0) return false
      return true
    };
    
    
    

    队列

    概念

    队列一个线性结构,特点是在某一端添加数据,在另一端删除数据,遵循先进先出的原则。

    实现

    这里会讲解两种实现队列的方式,分别是单链队列和循环队列。

    单链队列

    class Queue {
      constructor() {
        this.queue = []
      }
      enQueue(item) {
        this.queue.push(item)
      }
      deQueue() {
        return this.queue.shift()
      }
      getHeader() {
        return this.queue[0]
      }
      getLength() {
        return this.queue.length
      }
      isEmpty() {
        return this.getLength() === 0
      }
    }
    

    因为单链队列在出队操作的时候需要 O(n) 的时间复杂度,所以引入了循环队列。循环队列的出队操作平均是 O(1) 的时间复杂度。

    循环队列

    class SqQueue {
      constructor(length) {
        this.queue = new Array(length + 1)
        // 队头
        this.first = 0
        // 队尾
        this.last = 0
        // 当前队列大小
        this.size = 0
      }
      enQueue(item) {
        // 判断队尾 + 1 是否为队头
        // 如果是就代表需要扩容数组
        // % this.queue.length 是为了防止数组越界
        if (this.first === (this.last + 1) % this.queue.length) {
          this.resize(this.getLength() * 2 + 1)
        }
        this.queue[this.last] = item
        this.size++
        this.last = (this.last + 1) % this.queue.length
      }
      deQueue() {
        if (this.isEmpty()) {
          throw Error('Queue is empty')
        }
        let r = this.queue[this.first]
        this.queue[this.first] = null
        this.first = (this.first + 1) % this.queue.length
        this.size--
        // 判断当前队列大小是否过小
        // 为了保证不浪费空间,在队列空间等于总长度四分之一时
        // 且不为 2 时缩小总长度为当前的一半
        if (this.size === this.getLength() / 4 && this.getLength() / 2 !== 0) {
          this.resize(this.getLength() / 2)
        }
        return r
      }
      getHeader() {
        if (this.isEmpty()) {
          throw Error('Queue is empty')
        }
        return this.queue[this.first]
      }
      getLength() {
        return this.queue.length - 1
      }
      isEmpty() {
        return this.first === this.last
      }
      resize(length) {
        let q = new Array(length)
        for (let i = 0; i < length; i++) {
          q[i] = this.queue[(i + this.first) % this.queue.length]
        }
        this.queue = q
        this.first = 0
        this.last = this.size
      }
    }
    
    

    链表

    概念

    链表是一个线性结构,同时也是一个天然的递归结构。链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

    实现

    单向链表

    class Node {
      constructor(v, next) {
        this.value = v
        this.next = next
      }
    }
    class LinkList {
      constructor() {
        // 链表长度
        this.size = 0
        // 虚拟头部
        this.dummyNode = new Node(null, null)
      }
      find(header, index, currentIndex) {
        if (index === currentIndex) return header
        return this.find(header.next, index, currentIndex + 1)
      }
      addNode(v, index) {
        this.checkIndex(index)
        // 当往链表末尾插入时,prev.next 为空
        // 其他情况时,因为要插入节点,所以插入的节点
        // 的 next 应该是 prev.next
        // 然后设置 prev.next 为插入的节点
        let prev = this.find(this.dummyNode, index, 0)
        prev.next = new Node(v, prev.next)
        this.size++
        return prev.next
      }
      insertNode(v, index) {
        return this.addNode(v, index)
      }
      addToFirst(v) {
        return this.addNode(v, 0)
      }
      addToLast(v) {
        return this.addNode(v, this.size)
      }
      removeNode(index, isLast) {
        this.checkIndex(index)
        index = isLast ? index - 1 : index
        let prev = this.find(this.dummyNode, index, 0)
        let node = prev.next
        prev.next = node.next
        node.next = null
        this.size--
        return node
      }
      removeFirstNode() {
        return this.removeNode(0)
      }
      removeLastNode() {
        return this.removeNode(this.size, true)
      }
      checkIndex(index) {
        if (index < 0 || index > this.size) throw Error('Index error')
      }
      getNode(index) {
        this.checkIndex(index)
        if (this.isEmpty()) return
        return this.find(this.dummyNode, index, 0).next
      }
      isEmpty() {
        return this.size === 0
      }
      getSize() {
        return this.size
      }
    }
    
    

    相关文章

      网友评论

          本文标题:数据结构以及算法

          本文链接:https://www.haomeiwen.com/subject/dhoxwktx.html