栈是限定仅在表尾(栈顶)进行增删操作的线性表,但这并不意味着先进只能后出,后进先出的规则的前提的全部进栈。由于其是特殊的线性表,故也可从结构上划分为"顺序"或"链式"

顺序

    基本实现

    顺序存储结构借助JavaScript的数组即可实现,只需要将其增删操作限定在栈顶即可。因此只需要对外提供push和pop方法即黄色部分。红色部分则使用游标记录栈顶,在绿色部分,每一次新增都要判断是否栈满。相比线性表,栈的空间大小一开始确定后就不允许更改了

    空间共享

        由于栈在初始化后其栈长就是固定的,如果需要记录多个同类型数据,那么就要维护多个栈。这其实是无可厚非的。但是如果两个栈之间又有着紧密的关系,如股票买卖,有人买进一定是有人卖出,就比较难以明确的表示。此时可以让两个栈去共享空间。假设有数组a,其长度为10,该数组就相当于是总的发行股票。买进的那一波维护到数组b,卖出的那一波放到数组c。那么b+c等于10时即为栈满

    首先,初始化一个二维数组[[],[]],声明两个游标分别表示两个栈的栈顶

        那么先考虑极端的情况下,对于栈一来说,空栈时cursor_1=0,栈满时即maxSize-1;对于栈二而言,空栈时cursor_2为maxSize-1,栈满时为0。也就是说,栈1的栈顶在扩大,栈2在缩小

        由此可知,两栈栈满时,即两栈首尾相接时,cursor_1+1=cursor_2

链式

        这个和线性表中实现的单链表是一毛一样的,同样的,不允许挑选位置增删

通用栈

class Stack{

    constructor(maxSize,type){

        this.type = type

        this.cursor_2 = maxSize

        this.max = maxSize

         this.init(type)                                                         

    }

    init(type){

        if(type===1){

            this.cursor_1 = 0

            this.data = [] 

        }else if(type===2){

            this.cursor_1 = 0

            this.cursor_2 = this.max

            this.data = [[],[]]

        }

    }

    push(item,number){

        if(this.type===1){

            if(this.cursor_1===this.max){

                this.data.push(item)

                this.cursor_1++

                return 

            }

         if(this.cursor_1 + 1 == this.cursor_2){

            return false

          }else{

             if(number===1){

                this.data[number-1].push(item)                        

                this.cursor_1++

              }else if(number===2){

                this.data[number-1].push(item)                        

                this.cursor_2--

              }

         }

    }

    pop(number){

        if(this.type===1){

            if(this.cursor_1===0){

                return false

            }

            this.cursor_1--

            return  this.data.pop()

        }

        if(number===1){

            if(this.cursor_1===0){

                return false

            }

             this.cursor_1--                    

              return this.data[0].pop()

        }else if(number===2){

            if(this.cursor_2 === this.max){

                return false

            }

            this.cursor_2++                    

            return this.data[1].pop()

        }

    }

    getLast(number){

        if(this.type===1){

            return this.data[this.data.length-1]

        }

        return this.data[number][this.data[number].length-1]

    }

}

应用一:递归与撤销

        我们都知道,递归是基于上一步的操作结果计算一个新值。如果能借用栈去记录每一步的操作结果,便可以达到回退的能力。这让我想起了之前做的一个需求,大概是这样的:有一个页面,分上下结构,头部为发票的基本信息,底部为发票的分开开票列表。表格行内的每一行数据是可编辑的,在编辑的过程中需要根据开票数量和不含税单价动态计算勾稽金额并实时更新头部的总勾稽金额,为了避免误操作,在每一行和表头提供了撤销按钮,可撤回到上一步

        简化如下

        需求简化如下:

                当点击操作按钮时,获取salary的值对其进行加操作并更新到show元素,当点击了行内的撤销时,将结果撤回到改行操作时的上一条记录,并向总的栈中推入当前操作记录。总的撤销则按页面操作的每一步进行回退,这包含了行撤销

       实现代码如下

            获取操作按钮、初始化栈

            为行和总撤销按钮添加事件

            总撤销

            行编辑与撤销

        对于首次,页面如下

        当我们执行如下顺序(1-1-2-1-2-1)时,栈中的数据如下

(左侧为总的记录,右侧为1的操作记录)

            当需要撤销时,只需要取到上一次的值,即:总撤销得到的结果为20;行1撤销结果为18,并且总记录栈的最后一个元素为{key:0,data:18}

应用二:四则运算

你可能感兴趣的:(栈)