栈(stack)是一种运算受限的线性表。栈内的元素只允许通过列表的一端访问,这一端被称为栈顶,相对地,把另一端称为栈底。装羽毛球的盒子是现实中常见的栈例子。栈被称为一种后入先出(LIFO,last-in-first-out)的数据结构。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
下图演示了入栈和出栈的过程:
我们知道pop()方法虽然可以访问栈顶元素,但是调用该方法后,栈顶元素被删除,而peek()方法返回栈顶元素,并不改变栈。push(),pop(),peek()是实现栈的三个主要方法,下表定义了栈的主要方法:
dataStorage | Array | 存储数据的底层数据结构 |
top | int | 记录栈顶元素位置 |
push | fucntion | 入栈方法 |
pop | fucntion | 出栈方法 |
peek | fucntion | 返回栈顶元素 |
length | fucntion | 返回栈内元素个数 |
clear | function | 清空栈元素 |
栈的实现
构造方法:
1 function Stack() { 2 this.dataStorage = []; 3 this.top = 0; 4 this.push = push; 5 this.pop = pop; 6 this.peek = peek; 7 this.length = length; 8 this.clear = clear; 9 }
我们用数组来存储栈内元素,构造方法将其初始化为一个空数组,变量top记录栈顶元素位置,被构造方法初始化为0,表示栈顶元素的初始位置为0,当有元素入栈,top也随之改变。
push()方法的实现:
1 function push(element) { 2 this.dataStorage[this.top++] = element;//将元素保存在数组top位置,并指向下一空位置 3 }
当向栈中压入一个新元素时,需要将其保存在数组中变量 top 所对应的位置,然后将 top 值加 1,让其指向数组中下一个空位置。这里要特别注意 ++ 操作符的位置,它放在 this.top 的后面,这样新入栈的元素就被放在top 的当前值对应的位置,然后再将变量 top 的值加 1,指向下一个空位置。
pop方法的实现:
1 function pop() { 2 return this.dataStorage[--this.top];//返回数组top位置的元素,并让top指向top-1位置元素 3 }
pop() 方法恰好与 push() 方法相反——它返回栈顶元素,同时将变量 top 的值减 1。
peek() 方法的实现:
1 function peek() { 2 return this.dataStorage[this.top-1];//返回数组top-1位置的元素 3 }
这里需要考虑到空栈调用peek方法时候,返回的是-1位置元素,为undefined。
length()方法的实现:
1 function length() { 2 return this.top; 3 }
如果需要知道栈内到底存了多少个元素,可通过调用length()方法,栈元素的个数即top的值。
清空栈clear()饭方法的实现:
1 function clear() { 2 this.top = 0; 3 }
将top设置为0,即栈顶元素位置为0,此时为空栈。
下面我们来测试下:
1 var s = new Stack(); 2 s.push("a");//向栈顶压入元素 3 s.push("b"); 4 s.push("c"); 5 console.log(s.length());//输出栈内元素个数 6 console.log(s.pop());//返回栈顶元素并删除 7 console.log(s.length()); 8 console.log(s.peek());//返回栈顶元素不删除 9 s.clear(); 10 console.log(s.length()); 11 console.log(s.peek());
输出结果:
最后一行返回undefined,是因为栈内元素被清空后,栈顶无值。
Stack实际应用
我们来模拟一个简单的递归过程,计算数的阶乘。
先使用递归实现:
1 function Factorial(num) { 2 if (num == 0) { 3 return 1;//0的阶乘为1 4 } else { 5 return num*Factorial(num - 1); 6 } 7 8 }
用栈来计算,首先需要将数字1~num全部压入栈,然后将数字连乘。
1 function StackFactorial(num) { 2 var stack = new Stack(); 3 while (num > 1) { 4 stack.push(num--);//将1~num压入栈 5 } 6 var result = 1; 7 while (stack.length() > 0) { 8 result *= stack.pop();//连乘从栈顶取出的元素 9 } 10 return result; 11 }
测试结果:
1 console.log(Factorial(10));//输出3628800 2 console.log(StackFactorial(10));//输出3628800
本文的示例代码地址:https://github.com/LJunChina/JavaScript