栈是一种遵从后进先出(LIFO)原则的有序集合。新增加或待删除的元素都保存在栈的同一端,称作栈顶,另一端就是栈底。在栈里,新元素都靠近栈顶,旧元素都靠近栈底。例如,一摞书或者堆放起来的碗,新增加的在最顶部,旧的在最下面放着。
我们可以创建一个基于数组的栈。数组可以在任何位置添加或删除元素,用它来保存栈里的元素最好不过。栈遵循LIFO原则,需要对元素的插入和删除功能进行限制。我们为栈声明如下方法:
- push(element(s)): 添加一个(或几个)新元素到栈顶。
- pop(): 移除栈顶的元素,同时返回被移除的元素。
- peek(): 返回栈顶的元素,不对栈做任何修改,仅仅只是返回栈顶元素,不会移除它。
- isEmpty(): 如果栈里没有任何元素就返回true,否则返回false。
- clear(): 移除栈里的所有元素。
- size(): 返回栈里的元素个数。类似于数组的length属性。
class Stack {
constructor() {
this.items = [];
}
push(element) {
this.items.push(element);
}
pop() {
return this.items.pop();
}
peek() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
size() {
return this.items.length;
}
clear() {
this.items = [];
}
}
// 实例化一个栈
const stack = new Stack();
console.log(stack.isEmpty()); // true
stack.push(5);
stack.push(8);
console.log(stack.peek()); // 8
stack.push(10);
console.log(stack.size()); // 3
console.log(stack.isEmpty()); // false
stack.pop();
stack.pop();
console.log(stack.size()); // 1
使用数组来存储元素,栈的大部分方法的时间复杂度是O(n),因为最糟糕的情况下,我们需要迭代数组的所有位置才能找到我们要找的元素。如果数组长度更长,所需的时间会更长。
我们也可以使用一个对象来存储所有的栈元素,除了toString()方法,其他方法的复杂度均为O(1),我们可以直接找到目标元素进行操作。
class Stack = {
constructor() {
this.count = 0;
this.items = {};
}
push(element) {
this.items[this.count] = element;
this.count++;
}
size() {
return this.count;
}
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];
}
clear() {
this.items = {};
this.count = 0;
}
toString() {
if(this.isEmpty()) {
return '';
}
let objString = `${this.items[0]}`;
for(let i=1; i< this.count; i++) {
objString = `${objString},${this.items[i]}`;
}
return objString;
}
}
const stack = new Stack();
stack.push(2);
stack.push(5);
console.log(stack.toString()); // 2,2,5
栈的应用:实现十进制的数转换为2~36任意进制的值。我们使用上边定义的Stack类实现。
function baseConverter(decNumber, base) {
// 实例化余数栈,使用上文的Stack类
const remStack = new Stack();
// 余数对应的字符
const digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// 要转换的数字
let number = decNumber;
// 余数
let rem;
// 转换后的字符串
let baseString = '';
// 判断base在不在规则内
if(!(base >= 2 && base <= 36)) {
return '';
}
while(number > 0) {
rem = Math.floor(number % base);
remStack.push(rem);
number = Math.floor(number / base);
}
while(!remStack.isEmpty()) {
baseString += digits[remStack.pop()];
}
return baseString;
}
console.log(baseConverter(10, 2)); // 1010
console.log(baseConverter(100345, 2)); // 11000011111111001
console.log(baseConverter(100345, 8)); // 303771
console.log(baseConverter(100345, 16)); // 187F9
console.log(baseConverter(100345, 35)); // 2BW0