栈是一种特殊的列表,栈内的元素只能通过列表的一端访问,这一端称为栈顶,栈被称为一种
后入先出(LIFO,last-in-first-out)的数据结构。
由于栈具有后入先出的特点,所以任何不在栈顶的元素都无法访问。为了得到栈底的元 素,必须先拿掉上面的元素。
对栈的两种主要操作是将一个元素压入栈和将一个元素弹出栈。入栈使用 push() 方法,出 栈使用 pop() 方法。下图演示了入栈和出栈的过程 :
另一个常用的操作是预览栈顶的元素。pop() 方法虽然可以访问栈顶的元素,但是调用该方 法后,栈顶元素也从栈中被永久性地删除了。
peek() 方法则只返回栈顶元素,而不删除它。
为了记录栈顶元素的位置,同时也为了标记哪里可以加入新元素,我们使用变量 top,当向栈内压入元素时,该变量增大;从栈内弹出元素时,该变量减小。
栈还有其他的属性和方法,clear() 方法 清除栈内所有元素,length 属性记录栈内元素的个数。我们还定义了一个 empty 属性,用 以表示栈内是否含有元素,
不过使用 length 属性也可以达到同样的目的 。
1 function Stack(){ 2 this.dataStore = []; 3 this.top = 0; 4 this.push = push; 5 this.pop = pop; 6 this.peek = peek; 7 this.clear = clear; 8 this.length = length; 9 } 10 function push(elem){ //实现 push() 方法。当向栈中压入一个新元素时,需要将其保存在数组中变量 top 所对 应的位置,然后将 top 值加 1,让其指向数组中下一个空位置; 11 this.dataStore[this.top++] = elem; 12 } 13 function peek(){ //peek() 方法返回数组的第 top-1 个位置的元素,即栈顶元素 14 return this.dataStore[this.top-1]; 15 } 16 function pop(){ //pop() 方法恰好与 push() 方法相反——它返回栈顶元素,同时将变量 top 的值减 1 17 return this.dataStore[--this.top]; 18 } 19 function clear(){ //可以将变量 top 的值设为 0,轻松清空一个栈 20 this.top = 0; 21 } 22 function length(){ //length() 方法通过返回变量 top 值的方式返回栈 内的元素个数 23 return this.top; 24 }
测试Stack类的实现:
var s = new Stack(); s.push('aaaa'); s.push('bbbb'); s.push('cccc'); console.log('length: ' + s.length()); console.log(s.peek()); var poped = s.pop(); console.log('the poped element is:' + poped); console.log(s.peek()); s.clear(); console.log('length:' + s.length()); console.log(s.peek());
输出如下:
有一些问题特别适合用栈来解决。本节就介绍几个这样的例子。
1.数制间的相互转换
可以利用栈将一个数字从一种数制转化为另一种数制。假设想将数字n转化为以b为基数的数字,实现转换的算法如下:
- 最高位为n%b,将此位压入栈;
- 使用n/b代替n;
- 重复步骤1和2,直到n为0,且没有余数
- 持续将站内元素弹出,直到栈为空,一次将这些元素排列,就得到转换后数字的字符串形式;
注意:此算法只针对基数为2~9的情况。
2.回文
回文是指这样一种现象:一个单词、短语或数字,从前往后写和从后往前写都是一样的。
回文最简单的思路就是, 把元素反转后如果与原始的元素相等,那么就意味着这就是一个回文了
看看这个isPalindrome函数,其实就是通过调用Stack类,然后把传递进来的word这个元素给分解后的每一个组成单元给压入到
栈了,根据栈的原理,后入先出的原则,通过pop的方法在反组装这个元素,最后比较下之前与组装后的,如果相等就是回文了.
3.递归
栈常常被用来实现编程语言,使用栈实现递归即为一例 。
通过while把n = 5 递减压入栈,然后再通过一个循环还是根据栈的后入先出的原则,通过pop方法把最前面的取出来与product叠加.