本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-04-22
栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶。栈被称为一种后入先出 (LIFO, last-in-first-out) 的数据结构,由于这一点,所有任何不在栈顶的元素都无法访问,为了得到栈底的元素,必须先拿掉上面的元素。
对栈的两种主要操作是将一个元素压入栈和将一个元素弹出栈。入栈使用 push
方法,出栈使用 pop
方法;另一个常用的操作是预览栈顶的元素,pop
方法虽然可以访问栈顶的元素,但是调用该方法后,栈顶元素也从栈中被永久性地删除了,peek
方法则只返回栈顶元素,而不删除它。
为了记录栈顶元素的位置,同时也为了标记哪里可以加入新元素,我们使用变量 top
,当向栈内压入元素时该变量增大,从栈内弹出元素时,该变量减小。
除了以上介绍的,栈还有其他方法和属性,clear
方法清除栈内所有元素,length
方法返回栈内元素的个数,还定义了一个 empty
属性,用以表示栈内是否还有元素,不过使用 length
属性也可以达到同样的目的。
function Stack() {
this.dataStore = [];
this.top = 0;
this.push = push;
this.pop = pop;
this.peek = peek;
this.length = length;
this.clear = clear;
}
function push(element) {
this.dataStore[this.top++] = element;
}
function pop() {
return this.dataStore[--this.top]
}
function peek() {
return this.dataStore[this.top - 1]
}
function length() {
return this.top
}
function clear() {
this.top = 0;
}
测试Stack类的实现:
// example 1
var s = new Stack()
s.push('David')
s.push('Raymond')
s.push('Bryan')
console.log('length: ' + s.length()); // 3
console.log(s.peek()); // Bryan
var popped = s.pop()
console.log('The popped element is: ' + popped); // Bryan
console.log(s.top);
// 此时虽然 dataStore的数据没有被改变 ['David', 'Raymond', 'Bryan']
// 但是 top 的值被改变为2了
// 之后的push就是将 Bryan 替换成新元素,dataStore[top++] = '新值'
// peek就是返回 dataStore[top-1] = dataStore[1] = 'Raymond'
// 相当于通过暴露出来的方法 是永远无法再次访问到被pop的 'Bryan' 了
console.log(s.peek()); // Raymond
s.push('Cynthia')
console.log(s.peek()); // Cynthia
s.clear()
console.log('length: ' + s.length()); // 0
console.log(s.peek()); // undefined
s.push('Clayton')
console.log(s.peek()); // Clayton
可以利用栈将十进制数字转换成二至十六进制的数字。
原理如下:
实现如下:
function mulBase(num, base) {
if (base > 16 || base < 2) {
console.log('暂不支持该进制:' + base);
return
}
var s = new Stack();
do {
s.push(num % base)
num = Math.floor(num / base)
} while (num > 0)
var result = ''
while(s.length() > 0) {
var tmp = s.pop()
if (base > 10 && tmp > 9) {
tmp = String.fromCharCode(tmp + 55) // 10变成65 通过fromCharCode变成 'A'
}
result += tmp
}
return result
}
console.log(mulBase(32, 2)); // 100000
console.log(mulBase(125, 8)); // 175
console.log(mulBase(255, 16)); // FF
console.log(mulBase(2607, 16)); // A2F
console.log(mulBase(121, 11)); // 100
回文指这样一种现象:一个单词、短语和数字,从前往后写和从后往前写都是一样的,比如,“racecar” 、“1001” 、“A man, a plan, a canal: Panama”
使用栈可以轻松判断一个字符串是否是回文,我们将拿到的字符串的每个字符从左至右的顺序压入栈,当字符串的字符都入栈后,栈内就保存了一个反转后的字符串,第一个字符在栈底,然后持续弹出栈中的每个字符就可以得到一个新的字符串,该字符串与原来的字符串刚好相反,我们只需要比较这两个字符串是否相等即可。
function isPalindrome(word) {
var s = new Stack();
for (var i = 0; i < word.length; ++i) {
s.push(word[i])
}
var rword = '';
while (s.length() > 0) {
rword += s.pop()
}
return word === rword;
}
console.log(isPalindrome('racecar')); // true
console.log(isPalindrome('plan')); // false
使用字符串与数组的转换也可以完成这个功能:
function isPalindrome2(word) {
return word === word.split('').reverse().join('')
}
使用栈来模拟计算 5! 的过程,即5的阶乘,首先将数字从5到1压入栈,然后使用一个循环,将数字挨个弹出连乘,就得到了正确的答案。
function factorial(n) {
var s = new Stack();
while (n > 1) {
s.push(n--)
}
var product = 1;
while (s.length() > 0) {
product *= s.pop()
}
return product;
}