首页 » 学习JavaScript数据结构与算法(第2版) » 学习JavaScript数据结构与算法(第2版)全文在线阅读

《学习JavaScript数据结构与算法(第2版)》3.1 栈数据结构

关灯直达底部

栈是一种遵从后进先出(LIFO)原则的有序集合。新添加的或待删除的元素都保存在栈的同一端,称作栈顶,另一端就叫栈底。在栈里,新元素都靠近栈顶,旧元素都接近栈底。

在现实生活中也能发现很多栈的例子。例如,下图里的一摞书或者餐厅里堆放的盘子。

栈也被用在编程语言的编译器和内存中保存变量、方法调用等。

3.1.1 创建栈

我们将创建一个类来表示栈。让我们从基础开始,先声明这个类:

function Stack {  //各种属性和方法的声明}  

首先,我们需要一种数据结构来保存栈里的元素。可以选择数组:

let items = ;  

接下来,要为我们的栈声明一些方法。

  • push(element(s)):添加一个(或几个)新元素到栈顶。

  • pop:移除栈顶的元素,同时返回被移除的元素。

  • peek:返回栈顶的元素,不对栈做任何修改(这个方法不会移除栈顶的元素,仅仅返回它)。

  • isEmpty:如果栈里没有任何元素就返回true,否则返回false

  • clear:移除栈里的所有元素。

  • size:返回栈里的元素个数。这个方法和数组的length属性很类似。

3.1.2 向栈添加元素

我们要实现的第一个方法是push。这个方法负责往栈里添加新元素,有一点很重要:该方法只添加元素到栈顶,也就是栈的末尾。push方法可以这样写:

this.push = function(element){  items.push(element);};  

因为我们使用了数组来保存栈里的元素,所以可以用上一章里学到的数组的push方法来实现。

3.1.3 从栈移除元素

接着,我们来实现pop方法。这个方法主要用来移除栈里的元素。栈遵从LIFO原则,因此移出的是最后添加进去的元素。因此,我们可以用上一章讲数组时介绍的pop方法。栈的pop方法可以这样写:

this.pop = function{  return items.pop;};  

只能用pushpop方法添加和删除栈中元素,这样一来,我们的栈自然就遵从了LIFO原则。

3.1.4 查看栈顶元素

现在,为我们的类实现一些额外的辅助方法。如果想知道栈里最后添加的元素是什么,可以用peek方法。这个方法将返回栈顶的元素:

this.peek = function{  return items[items.length-1];};  

因为类内部是用数组保存元素的,所以访问数组的最后一个元素可以用 length - 1

在上图中,有一个包含三个元素的栈,因此内部数组的长度就是3。数组中最后一项的位置是2,length - 1(3-1)正好是2。

3.1.5 检查栈是否为空

下一个要实现的方法是 isEmpty,如果栈为空的话将返回true,否则就返回false

this.isEmpty = function{  return items.length == 0;};  

使用isEmpty方法,我们能简单地判断内部数组的长度是否为0。

类似于数组的length属性,我们也能实现栈的length。对于集合,最好用size代替length。因为栈的内部使用数组保存元素,所以能简单地返回栈的长度:

this.size = function{  return items.length;};  

3.1.6 清空和打印栈元素

最后,我们来实现clear方法。clear方法用来移除栈里所有的元素,把栈清空。实现这个方法最简单的方式是:

this.clear = function{  items = ;};  

另外也可以多次调用pop方法,把数组中的元素全部移除,这样也能实现clear方法。

完成了!栈已经实现。通过一个例子来放松一下:为了检查栈里的内容,我们来实现一个辅助方法,叫print。它会把栈里的元素都输出到控制台:

this.print = function{  console.log(items.toString);};  

这样,我们就完整创建了栈!

使用Stack

在深入了解栈的应用前,我们先来学习如何使用Stack类。

首先,我们需要初始化Stack类。然后,验证一下栈是否为空(输出是 true,因为还没有往栈里添加元素)。

let stack = new Stack;console.log(stack.isEmpty); //输出为true  

接下来,往栈里添加一些元素(这里我们添加数字5和8;你可以添加任意类型的元素):

stack.push(5);stack.push(8);  

如果调用peek方法,将会输出8,因为它是往栈里添加的最后一个元素:

console.log(stack.peek); //输出8  

再添加一个元素:

stack.push(11);console.log(stack.size); //输出3console.log(stack.isEmpty); //输出false  

我们往栈里添加了11。如果调用size方法,输出为3,因为栈里有三个元素(5、8和11)。如果我们调用isEmpty方法,会看到输出了false(因为栈里有三个元素,不是空栈)。最后,我们再添加一个元素:

stack.push(15);  

下图描绘了目前为止我们对栈的操作,以及栈的当前状态:

然后,调用两次pop方法从栈里移除2个元素:

stack.pop;stack.pop;console.log(stack.size); //输出2stack.print; //输出[5, 8]  

在两次调用pop方法前,我们的栈里有四个元素。调用两次后,现在栈里仅剩下5和8了。下图描绘这个过程的执行: