Skip to content

stack)是一种遵循先入后出逻辑的线性数据结构。

我们可以将栈类比为桌面上的一摞盘子,如果想取出底部的盘子,则需要先将上面的盘子依次移走。

我们将盘子替换为各种类型的元素(如整数、字符、对象等),就得到了栈这种数据结构。

1.基于数组的实现

js
/* 基于数组实现的栈 */
class ArrayStack {
  #stack
  constructor() {
    this.#stack = []
  }

  /* 获取栈的长度 */
  get size() {
    return this.#stack.length
  }

  /* 判断栈是否为空 */
  isEmpty() {
    return this.#stack.length === 0
  }

  /* 入栈 */
  push(num) {
    this.#stack.push(num)
  }

  /* 出栈 */
  pop() {
    if (this.isEmpty()) throw new Error('栈为空')
    return this.#stack.pop()
  }

  /* 访问栈顶元素 */
  top() {
    if (this.isEmpty()) throw new Error('栈为空')
    return this.#stack[this.#stack.length - 1]
  }

  /* 返回 Array */
  toArray() {
    return this.#stack
  }
}

2.基于链表的实现

js
/* 基于链表实现的栈 */
class LinkedListStack {
  #stackPeek // 将头节点作为栈顶
  #stkSize = 0 // 栈的长度

  constructor() {
    this.#stackPeek = null
  }

  /* 获取栈的长度 */
  get size() {
    return this.#stkSize
  }

  /* 判断栈是否为空 */
  isEmpty() {
    return this.size === 0
  }

  /* 入栈 */
  push(num) {
    const node = new ListNode(num)
    node.next = this.#stackPeek
    this.#stackPeek = node
    this.#stkSize++
  }

  /* 出栈 */
  pop() {
    const num = this.peek()
    this.#stackPeek = this.#stackPeek.next
    this.#stkSize--
    return num
  }

  /* 访问栈顶元素 */
  peek() {
    if (!this.#stackPeek) throw new Error('栈为空')
    return this.#stackPeek.val
  }

  /* 将链表转化为 Array 并返回 */
  toArray() {
    let node = this.#stackPeek
    const res = new Array(this.size)
    for (let i = res.length - 1; i >= 0; i--) {
      res[i] = node.val
      node = node.next
    }
    return res
  }
}

3.应用

  • 浏览器中的后退与前进、软件中的撤销与反撤销。每当我们打开新的网页,浏览器就会对上一个网页执行入栈,这样我们就可以通过后退操作回到上一个网页。后退操作实际上是在执行出栈。如果要同时支持后退和前进,那么需要两个栈来配合实现。
  • 程序内存管理。每次调用函数时,系统都会在栈顶添加一个栈帧,用于记录函数的上下文信息。在递归函数中,向下递推阶段会不断执行入栈操作,而向上回溯阶段则会不断执行出栈操作。