真正的大师永远都怀着一颗学徒的心。——易大师
栈!
- 什么是栈?
- 栈的增加/删除:
- 栈常用的辅助方法:
- 封装栈:
- 封装栈的实际应用例子:
- 十进制转二进制(辗转相除法):
- 十进制转任意进制:
- 栈和数组的区别:
- 栈和数组对比的应用场景:
- 栈-前端应用场景举例:
- 页面路由历史管理:
- 撤销操作:
- 递归函数调用栈:
什么是栈?
栈是一种特殊的线性数据结构,它只允许在一端进行插入和删除操作,这一端被称为栈顶,相对的另一端称为栈底。 栈按照后进先出 Last in First Out(LIFO)的原则存储数据,即最后进入栈的数据会最先被删除。【限定仅在表尾进行插入和删除操作的线性表】
栈的增加/删除:
- Stack增加使用 push() 方法
- Stack删除使用 pop() 方法
可以理解为栈是一个特殊的数组。
栈常用的辅助方法:
方法/属性 | 作用 | 示例 |
---|---|---|
length | 获取当前栈元素数量 | if (stack.length === 0) {…} |
peek() | 查看栈顶元素(需自定义实现) | function peek() { return stack.at(-1) } |
isEmpty() | 判断栈是否为空(需自定义实现) | function isEmpty() { return stack.length === 0 } |
… | … | … |
封装栈:
// push添加一个元素到栈顶// pop出栈// peek 返回栈顶// isEmpty() 判断栈是否为空// clear() 清空栈结构// size() 栈的元素个数// toString() 转换成普通的字符串class Stack{// 这里的#是私有的 es13中提到#items = [];pop(){return this.#items.pop();}push(data){this.#items.push(data);}peek(){// return this.#items[this.items.length - 1];return this.#items.at(-1);}isEmpty(){return this.#items.length === 0;}clear(){this.#items = [];}size(){return this.#items.length;}toString(){return this.#items.join("");}}let stack = new Stack();
封装栈的实际应用例子:
十进制转二进制(辗转相除法):
接上面栈的代码:
function convert (decNumber) {let remStack = new Stack();let string = "";let number = decNumber;while (number > 0) {remStack.push(number % 2);number = Math.floor(number / 2);}while (!(remStack.isEmpty())) {string += remStack.pop();}return string;}console.log('50转为二进制是:', convert(50));
十进制转任意进制:
function convert (decNumber, base) {let remStack = new Stack();let string = "";let number = decNumber;let baseString = "0123456789ABCDEF"while (number > 0) {remStack.push(number % base);number = Math.floor(number / base);}while (!(remStack.isEmpty())) {string += baseString[remStack.pop()];}return string;}convert(50, 2);convert(50, 8);convert(50, 16);
栈和数组的区别:
特性 | 数组 | 栈 |
---|---|---|
操作方式 | 自由增删改查(通过索引) | 仅允许push(入栈)、pop(出栈) |
访问权限 | 任意位置直接访问 | 仅能访问栈顶元素 |
底层实现 | 内存中的连续空间 | 可用数组或链表实现 |
灵活性 | 高(可动态扩容或缩容) | 低(严格遵循LIFO规则) |
栈和数组对比的应用场景:
- 数组 :适合需要快速随机访问的场景,如排序算法、矩阵运算、数据缓存等。
- 栈:适合需要回溯或反转顺序的场景,如函数调用栈、括号匹配、表达式求值、浏览器前进后退等。
栈-前端应用场景举例:
页面路由历史管理:
// 模拟浏览器后退栈
const historyStack = new Stack();
historyStack.push("/home");
historyStack.push("/detail");
historyStack.pop(); // 返回上一页
撤销操作:
const undoStack = new Stack();
const redoStack = new Stack();function doAction(action) {undoStack.push(action);redoStack.items = []; // 清空重做栈
}
递归函数调用栈:
代码举例计算阶乘:n × (n-1) × … × 1
function factorial(n, stack = new Stack()) {stack.push(`计算 factorial(${n})`);if (n === 1) return 1;const result = n * factorial(n - 1, stack);stack.pop(); // 调用完成出栈return result;
}