【JavaScript数据结构】栈

47 阅读2分钟

使用数组实现栈相对简单,因为JavaScript的数组本身就提供了入栈和出栈的方法(pushpop)。下面是使用数组实现栈及其常见操作的代码:

class Stack {
  constructor() {
    this.items = []; // 使用数组来存储栈的元素
  }

  // 入栈操作
  push(element) {
    this.items.push(element); // 使用数组的push方法
  }

  // 出栈操作
  pop() {
    if (this.isEmpty()) return null; // 如果栈为空,返回null
    return this.items.pop(); // 使用数组的pop方法
  }

  // 查看栈顶元素,但不弹出
  peek() {
    return this.isEmpty() ? null : this.items[this.items.length - 1]; // 返回数组的最后一个元素
  }

  // 检查栈是否为空
  isEmpty() {
    return this.items.length === 0;
  }

  // 获取栈的大小
  size() {
    return this.items.length;
  }

  // 清空栈
  clear() {
    this.items = [];
  }
}

我们可以使用数组实现栈的功能,但为了更直观地展示栈的工作机制,这里我们将使用链表来实现。

// 定义栈节点
class StackNode {
  constructor(value) {
    this.value = value;   // 当前节点的值
    this.next = null;    // 指向下一个节点的引用
  }
}

class Stack {
  constructor() {
    this.top = null;  // 栈顶
    this.size = 0;    // 栈的大小
  }

  // 入栈操作
  push(value) {
    let newNode = new StackNode(value);
    if (this.top) {
      newNode.next = this.top;
    }
    this.top = newNode;
    this.size++;
  }

  // 出栈操作
  pop() {
    if (!this.top) return null;
    
    let poppedValue = this.top.value;
    this.top = this.top.next;
    this.size--;
    return poppedValue;
  }

  // 查看栈顶元素,但不弹出
  peek() {
    return this.top ? this.top.value : null;
  }

  // 检查栈是否为空
  isEmpty() {
    return this.size === 0;
  }
}

单调栈是一种特殊的栈,它可以在 O(n) 的时间复杂度内解决一系列与单调性有关的问题,例如找到数组中每个元素的下一个更大元素。

单调栈通常维持一个单调递增或递减的顺序。以下是一个单调递增栈的示例及其详细注释:

class MonotonicStack {
  constructor() {
    this.stack = [];  // 使用数组来实现栈的功能
  }

  // 入栈操作
  push(value) {
    // 为了维持栈的单调性,将栈顶元素小于当前值的元素全部弹出
    while (this.stack.length > 0 && this.stack[this.stack.length - 1] < value) {
      this.stack.pop();
    }
    this.stack.push(value);
  }

  // 出栈操作
  pop() {
    return this.stack.pop();
  }

  // 查看栈顶元素,但不弹出
  peek() {
    return this.stack.length > 0 ? this.stack[this.stack.length - 1] : null;
  }

  // 检查栈是否为空
  isEmpty() {
    return this.stack.length === 0;
  }
}

使用单调栈解决问题: 找到一个数组中每个元素的下一个更大元素。

function nextGreaterElement(nums) {
  let res = new Array(nums.length).fill(-1); // 初始化结果数组,将所有元素设为-1
  let stack = []; // 使用数组来实现单调栈,存储的是元素的索引

  for (let i = 0; i < nums.length; i++) {
    // 当栈不为空且当前元素大于栈顶元素时
    while (stack.length > 0 && nums[i] > nums[stack[stack.length - 1]]) {
      let idx = stack.pop(); // 弹出栈顶元素(索引)
      res[idx] = nums[i];   // 更新结果数组
    }
    stack.push(i); // 将当前元素的索引入栈
  }

  return res;
}

console.log(nextGreaterElement([2, 1, 2, 4, 3]));  // 输出: [4, 2, 4, -1, -1]

上述代码中,nextGreaterElement函数使用了单调栈来高效地解决问题。当栈中还有元素且当前元素大于栈顶元素时,这意味着当前元素就是栈顶元素对应值的下一个更大元素。

单调栈是算法面试和在线评测中的常见工具,学会如何使用和实现它非常有益。