栈是一种遵从后进先出(LIFO)原则的有序集合。新添加或待删除的元素都保持在栈的同一端, 称为栈顶,另一端就叫栈底。 在栈里, 新元素都靠近栈顶, 旧元素都接近栈底。
在现实生活中的例子就是下图里的一摞书或者餐厅里叠放的盘子。
栈也被用在编程语言的编译器和内存中保存变量、方法调用等, 也用于浏览器历史记录(浏览器的返回按钮)。
创建一个基于JavaScript对象是stack类
创建一个Stack类的最简单的方式是使用数组来存储其元素。在处理大量数据的时候(这在现实生活中的项目里很常见),我们同样需要评估如何操作数据是最高效的。在使用数组时,大部分方法的时间复杂度是O(n)。我们需要迭代整个数组直到找到要找的那个元素, 在最坏的情况下需要迭代数组的所有位置。 其中的n代表数组的长度。 如果数组有更多元素的话, 所需要的时间会更长。 另外,数组是一个有序集合, 为了保证元素排列有序, 它会占用更多的内存空间。 所以,我们可以使用一个JavaScript对象来存储所有的栈元素, 保证它们的顺序并且遵守LIFO原则。
首先声明一个Stack类
class Stack {
constructor() {
this.count = 0;
this.items = {};
}
}
- 向栈中插入元素
push(item) {
this.items[this.count] = item;
this.count++;
}
- 验证一个栈是否为空和它的大小
count属性也表示栈的大小。因此,我们可以简单的返回count的属性的值来实现size方法。
size() {
return this.count;
}
- 验证栈是否为空,可以简单的判断count是否为0
isEmpty() {
return this.count === 0;
}
- 从栈中弹出元素
pop() {
if(this.isEmpty()) {
return undefined;
}
this.count--;
const result = this.items[this.count];
delete this.items[this.count];
return result;
}
- 查看栈顶的值
peek() {
if(this.isEmpty()) {
return undefined;
}
return this.items[this.count - 1];
}
6.清空栈
clear() {
this.items = {};
this.count = 0;
}
经典应用
使用栈结构去实现进制的转换。我们知道进制的转换是利用除基倒取余的方式去实现的。 即将数除以需要转换的进制数,得到商和余。只要商不为0。则继续除下去。取余数。最终将余数倒序排列完成转换。 这里就符合栈中的先进后出(FILO)。
- 实现二进制的转换
function convert(num) {
const stack = new Stack();
let str = '';
while(num / 2 !==0) {
stack.push(num % 2);
num = Math.floor(num / 2);
}
while (!stack.isEmpty()) {
str = `${str}${stack.pop()}`
}
return str;
}
- 任意进制的转换
/**
* @param decNumber {number} 需要进行进制转换的数字
* @param base {number} 进制转换的数字
*/
function baseConverter(decNumber, base) {
const stack = new Stack();
const digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let str = "";
while (decNumber / base !== 0) {
stack.push(decNumber % base);
decNumber = Math.floor(decNumber / base);
}
while (!stack.isEmpty()) {
str = `${str}${digits.charAt(Number(stack.pop()))}`;
}
return str;
}
leetCode算法题
- 二叉树的前序遍历
对于没有二叉树数据结构认识的同学,数据结构-二叉树