JavaScript常用数据结构(栈(Stack)详解)

栈是一种相当有用而又非常简单的数据结构,它的基本特点是先进后出或后进先出,也就是先入栈的数据,最后才出栈,最后入栈的数据先出栈。

JavaScript常用数据结构(栈(Stack)详解)

文章图片
以下几个基本的栈操作:
  1. push:添加一个数据到栈中,如果栈已满,则拒绝添加数组,提示溢出警告。
  2. pop:从栈顶删除一个数据,pop的数据顺序和push的顺序相反,如果栈为空,则不做任何操作。
  3. peek或top:返回栈顶数据。
  4. isEmpty:如果栈为空则返回true,否则返回false。
JavaScript常用数据结构(栈(Stack)详解)

文章图片
如何理解栈?栈的实际应用非常多,可以说开发中几乎无处不在,连计算机提供给软件运行的方式也是使用栈的形式。如何理解栈呢?假设你有10本相同的书,将它们都整齐叠起来,这就是栈,然后只能从顶部取一本书。底部的书最先叠的,它是在最后才能取到,最后叠的一本书在顶部,这本书会被最先取出,这就是先进后出或后进先出。
栈操作的时间复杂度:push(),pop(),peek(),isEmpty()的时间复杂度均为O(1)。
栈的应用栈的应用有哪些?下面是一些例子:
  1. 表达式的语法检查,例如数学表达式中的括号都是成对出现的,可以将所有的类似的符号入栈,发现有匹配则出栈,处理完成后如果发现栈不为空,则表达式语法错误。
  2. 表达式中缀到后缀/前缀的转换。
  3. 在编辑器,如Photoshop等很多地方都有的撤销功能。
  4. Web浏览器的前进和后退功能。
  5. 其它很多高级算法中都有使用到栈,特别是使用栈实现DFS遍历,例如汉诺塔,树遍历,股票跨度问题,直方图问题。
  6. 其它应用例如:回溯算法,骑士旅行问题,迷宫问题,N皇后问题和数独问题等。
  7. 在图论算法中,栈用到的地方有拓扑排序和强连通分量。
栈的实现方式栈可以使用两种方式实现:
  1. 使用数组实现栈。
  2. 使用链表实现栈。
先看第一种使用数组实现栈的代码,其中该实现方式中使用一个top索引指示栈顶,top的初始值为-1,push一个数组,top为1,以后再push则top继续增加。执行pop的时候只需要将top-1即可。
使用数组实现的优点是:实现简单,不需要使用额外的内存保存指针,缺点是:它不是动态的,也就是说数组的大小是固定的,只适用于知道数据量上界的情况。
使用数组实现栈的代码如下:
// 使用数组实现栈 function ArrayStack(capacity){ if(capacity < 3){ console.log("capacity is too small."); return null; } this.capacity = capacity; this.array = new Array(capacity); this.top = -1; }// 检查栈是否已空 ArrayStack.prototype.isEmpty = function(){ return this.top == -1; }// 往栈添加一个数据 ArrayStack.prototype.push = function(value){ if(this.top == this.capacity - 1){ console.log("overflow: could not push data."); return; } this.array[++this.top] = value; }// 从栈顶取出一个数据 ArrayStack.prototype.pop = function(){ if(this.top == -1) return null; return this.array[this.top--]; }// 查看栈顶元素 ArrayStack.prototype.peek = function(){ if(this.top == -1) return null; return this.array[this.top]; }// 调用实例 var stack = new ArrayStack(10); for(var i = 0; i < 10; i++){ stack.push(i * i + 99); } var str = ""; while(!stack.isEmpty()){ var value = http://www.srcmini.com/stack.peek(); str += value +" "; stack.pop(); } console.log(str);

【JavaScript常用数据结构(栈(Stack)详解)】第二种实现栈的方式是使用链表,使用链表的好处是不需要预先申请内存,可以在运行时决定,缺点是需要额外的内存储存指针。在数据量上界不知道的时候,应首选栈的方式,其实现代码如下:
// 使用链表实现栈// 结点 function Node(value){ this.value = http://www.srcmini.com/value; this.next = null; }// 栈 function LinkedStack(){ this.size = 0; this.top = null; }// 检查栈是否已空 LinkedStack.prototype.isEmpty = function(){ return this.size == 0; }// push操作 LinkedStack.prototype.push = function(value){ var node = new Node(value); node.next = this.top; this.top = node; this.size++; }// pop操作 LinkedStack.prototype.pop = function(){ if(this.size == 0) return; var top = this.top; var value = top.value; this.top = top.next; top = null; this.size--; return value; }// peek操作 LinkedStack.prototype.peek = function(){ if(this.size == 0) return null; return this.top.value; }// 使用实例 var stack = new LinkedStack(); for(var i = 0; i < 10; i++) stack.push(i * i * i + 2); var str =""; while(!stack.isEmpty()){ str += stack.peek() + " "; stack.pop(); } console.log(str);

    推荐阅读