栈(Stack)是一种常见且重要的数据结构,它遵循后进先出(LIFO)的原则,即最后入栈的元素最先出栈。栈在计算机科学中应用广泛,例如函数调用栈、表达式求值、浏览器历史记录等。
一、栈的基本操作
栈通常支持以下基本操作:
push(element): 将元素压入栈顶。
pop(): 移除并返回栈顶元素。
peek(): 返回栈顶元素,但不移除它。
isEmpty(): 判断栈是否为空。
size(): 返回栈中元素的个数。
clear(): 清空栈。
二、使用数组实现栈
在 JavaScript 中,我们可以使用数组来模拟栈的行为。数组的 push() 和 pop() 方法正好对应栈的入栈和出栈操作。
class Stack {
constructor() {
this.items = [];
}
// 入栈
push(element) {
this.items.push(element);
}
// 出栈
pop() {
if (this.isEmpty()) {
return"Stack is empty";
}
returnthis.items.pop();
}
// 查看栈顶元素
peek() {
if (this.isEmpty()) {
return"Stack is empty";
}
returnthis.items[this.items.length - 1];
}
// 判断栈是否为空
isEmpty() {
returnthis.items.length === 0;
}
// 返回栈的大小
size() {
returnthis.items.length;
}
// 清空栈
clear() {
this.items = [];
}
}
// 堆代码 duidaima.com
// 测试代码
const stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.peek()); // 3
console.log(stack.pop()); // 3
console.log(stack.size()); // 2
stack.clear();
console.log(stack.isEmpty()); // true
三、栈的应用场景
1. 函数调用栈
JavaScript 引擎使用栈来管理函数调用。每次调用函数时,都会创建一个新的栈帧并将其压入栈顶。栈帧中存储了函数的局部变量、参数和返回地址等信息。当函数执行完毕后,其对应的栈帧会被弹出,程序继续执行上一个栈帧中的代码。
2. 括号匹配
栈可以用来检查表达式中的括号是否匹配。例如,我们可以遍历表达式,遇到左括号就入栈,遇到右括号就出栈并检查是否匹配。
function isBalanced(expression) {
const stack = new Stack();
const brackets = { "(": ")", "{": "}", "[": "]" };
for (let char of expression) {
if (brackets[char]) {
stack.push(char);
} elseif (Object.values(brackets).includes(char)) {
if (stack.isEmpty() || brackets[stack.pop()] !== char) {
returnfalse;
}
}
}
return stack.isEmpty();
}
console.log(isBalanced("({[]})")); // true
console.log(isBalanced("({[})")); // false
3. 进制转换
栈可以用来将十进制数转换为其他进制数。例如,我们可以不断地将十进制数除以目标进制,并将余数入栈,最后将栈中的元素依次弹出即可得到结果。
function baseConverter(decNumber, base) {
const stack = new Stack();
const digits = "0123456789ABCDEF";
while (decNumber > 0) {
stack.push(decNumber % base);
decNumber = Math.floor(decNumber / base);
}
let result = "";
while (!stack.isEmpty()) {
result += digits[stack.pop()];
}
return result || "0";
}
console.log(baseConverter(100, 2)); // 1100100
console.log(baseConverter(100, 8)); // 144
console.log(baseConverter(100, 16)); // 64
4. 深度优先搜索(DFS)
在图和树的遍历算法中,深度优先搜索(DFS)是一种常见的方法。DFS 使用栈来存储待访问的节点,从而实现深度优先的遍历。
class Graph {
constructor() {
this.adjacencyList = newMap();
}
addVertex(vertex) {
this.adjacencyList.set(vertex, []);
}
addEdge(vertex1, vertex2) {
this.adjacencyList.get(vertex1).push(vertex2);
this.adjacencyList.get(vertex2).push(vertex1);
}
dfs(startVertex) {
const stack = new Stack();
const visited = newSet();
stack.push(startVertex);
visited.add(startVertex);
while (!stack.isEmpty()) {
const currentVertex = stack.pop();
console.log(currentVertex);
for (const neighbor ofthis.adjacencyList.get(currentVertex)) {
if (!visited.has(neighbor)) {
stack.push(neighbor);
visited.add(neighbor);
}
}
}
}
}
// 测试代码
const graph = new Graph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('B', 'D');
graph.addEdge('C', 'D');
graph.dfs('A'); // A, C, D, B
四、总结
通过理解栈的基本操作和应用场景,我们可以更好地利用它来解决实际问题。除了数组,我们还可以使用链表等其他数据结构来实现栈。不同的实现方式各有优缺点,需要根据具体场景进行选择。