使用数组实现栈相对简单,因为JavaScript的数组本身就提供了入栈和出栈的方法(push 和 pop)。下面是使用数组实现栈及其常见操作的代码:
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函数使用了单调栈来高效地解决问题。当栈中还有元素且当前元素大于栈顶元素时,这意味着当前元素就是栈顶元素对应值的下一个更大元素。
单调栈是算法面试和在线评测中的常见工具,学会如何使用和实现它非常有益。