Stack
栈(LIFO)数据结构,后进先出。
函数签名
typescript
function createStack<T>(): Stack<T>
interface Stack<T> {
push(item: T): void
pop(): T | undefined
peek(): T | undefined
size(): number
isEmpty(): boolean
clear(): void
toArray(): T[]
}API 说明
push(item: T): void
在栈顶添加元素。
参数:
item: 要添加的元素
时间复杂度:O(1)
pop(): T | undefined
移除并返回栈顶的元素。
返回值:
- 栈顶的元素,如果栈为空则返回
undefined
时间复杂度:O(1)
peek(): T | undefined
查看栈顶的元素,但不移除。
返回值:
- 栈顶的元素,如果栈为空则返回
undefined
时间复杂度:O(1)
size(): number
获取栈中元素的数量。
返回值:
- 栈中元素的数量
时间复杂度:O(1)
isEmpty(): boolean
检查栈是否为空。
返回值:
- 如果栈为空则返回
true,否则返回false
时间复杂度:O(1)
clear(): void
清空栈中的所有元素。
时间复杂度:O(1)
toArray(): T[]
返回栈中所有元素的数组副本(栈顶在前)。
返回值:
- 包含所有元素的数组(逆序)
时间复杂度:O(n)
使用示例
typescript
import { createStack } from '@shared/functions/data-structures/Stack'
// 创建栈
const stack = createStack<string>()
// 入栈操作
stack.push('命令1')
stack.push('命令2')
stack.push('命令3')
// 查看栈顶
console.log(stack.peek()) // '命令3'
// 出栈操作
console.log(stack.pop()) // '命令3'
console.log(stack.pop()) // '命令2'
// 获取栈大小
console.log(stack.size()) // 1
// 检查是否为空
console.log(stack.isEmpty()) // false
// 转换为数组(栈顶在前)
console.log(stack.toArray()) // ['命令1']
// 清空栈
stack.clear()
console.log(stack.isEmpty()) // true工作原理
栈是一种后进先出(LIFO)的数据结构,类似于一叠盘子:
- 新元素总是添加到栈顶(push)
- 移除操作总是从栈顶开始(pop)
- 后加入的元素先被移除
本实现使用数组作为底层数据结构:
push使用数组的push方法 - O(1)pop使用数组的pop方法 - O(1)peek访问数组最后一个元素 - O(1)
应用场景
- 函数调用栈:程序执行时管理函数调用
- 撤销/重做功能:编辑器的操作历史
- 表达式求值:计算器中的中缀表达式转后缀
- 括号匹配:检查括号是否配对
- 深度优先搜索(DFS):图的遍历算法
- 浏览器历史记录:后退功能
经典算法
括号匹配
typescript
function isValidParentheses(s: string): boolean {
const stack = createStack<string>()
const pairs: Record<string, string> = { ')': '(', ']': '[', '}': '{' }
for (const char of s) {
if (['(', '[', '{'].includes(char)) {
stack.push(char)
} else if (char in pairs) {
if (stack.isEmpty() || stack.pop() !== pairs[char]) {
return false
}
}
}
return stack.isEmpty()
}
console.log(isValidParentheses('()[]{}')) // true
console.log(isValidParentheses('([)]')) // false后缀表达式求值
typescript
function evalRPN(tokens: string[]): number {
const stack = createStack<number>()
for (const token of tokens) {
if (['+', '-', '*', '/'].includes(token)) {
const b = stack.pop()!
const a = stack.pop()!
switch (token) {
case '+': stack.push(a + b); break
case '-': stack.push(a - b); break
case '*': stack.push(a * b); break
case '/': stack.push(Math.trunc(a / b)); break
}
} else {
stack.push(Number(token))
}
}
return stack.pop()!
}
console.log(evalRPN(['2', '1', '+', '3', '*'])) // 9 = (2 + 1) * 3