你有没有在厨房里叠过盘子?最上面放上去的,总是最先被拿走。这种“后进先出”的逻辑,正是栈的核心思想。在编程中,栈是一种基础但极其重要的数据结构,用好了能解决不少实际问题。
栈是什么
栈(Stack)就像一摞书,只能从顶部添加或取出元素。它有两个基本操作:压入(push)和弹出(pop)。压入是把新元素放到栈顶,弹出则是移除并返回栈顶元素。还有一种常见操作是查看栈顶元素但不移除,叫作 peek 或 top。
动手实现一个栈
我们用 JavaScript 来写一个简单的栈类。不需要复杂的东西,数组就能轻松模拟栈的行为。
class Stack {
constructor() {
this.items = [];
}
// 压入元素
push(element) {
this.items.push(element);
}
// 弹出元素
pop() {
if (this.isEmpty()) {
return undefined;
}
return this.items.pop();
}
// 查看栈顶元素
peek() {
if (this.isEmpty()) {
return undefined;
}
return this.items[this.items.length - 1];
}
// 检查是否为空
isEmpty() {
return this.items.length === 0;
}
// 获取栈的大小
size() {
return this.items.length;
}
// 清空栈
clear() {
this.items = [];
}
}
这个栈类很轻巧,所有方法都围绕数组操作展开。比如 push 和 pop 直接调用数组原生方法,而 peek 只是读取最后一个元素,不改动结构。
实际用一用
假设你在写一个浏览器前进后退功能。每次点击新页面,就把它压入历史栈;点“返回”时,就从栈里弹出上一个页面。虽然真实场景会更复杂,但原理就是这样。
const history = new Stack();
history.push('首页');
history.push('文章页');
history.push('详情页');
console.log(history.peek()); // 输出:详情页
console.log(history.pop()); // 输出:详情页
console.log(history.size()); // 输出:2
代码跑起来很直观。每一步操作都符合直觉,也容易调试。你甚至可以在控制台一步步试,看着栈的变化。
为什么不直接用数组
有人会问,JavaScript 数组本来就能 push 和 pop,何必再包一层?关键在于抽象。封装成栈类之后,接口更清晰,别人一看就知道这是“后进先出”的结构,不会误用 shift 或 unshift 破坏逻辑。而且将来想换底层实现(比如用对象模拟),外部代码也不用改。
栈虽小,五脏俱全。掌握它,不只是为了刷题,更是理解程序运行机制的一扇门——函数调用栈、表达式求值、括号匹配,背后都有它的影子。