JavaScript数据结构——栈(2)

93 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

前言

上期我们基于数组的创建了一个栈类,但是并不是最完美的,首先他会消耗更多的内存空间,其次在数据量过大时,消耗的时间会更久。本期我们基于对象实现一个栈类。

我们先来回顾一下,栈都拥有哪些方法:

  • push :添加一个元素到栈顶(因为存储结构的变化,目前只做添加单个元素)

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

  • top :返回栈顶的元素,不对栈进行任何处理

  • isNull :判断栈是否为空,如果为空返回true,否则返回false

  • clear :清空栈

  • size :返回栈的元素个数

编码实现

定义一个栈类

class Stack{
    constructor(){
        // 基于对象存储
        this.items = {}
        // 定义一个变量,辅助存储栈并获得栈的大小
        this.nums = 0
    }
}

push

push(data){
    this.items[this.nums] = data
    this.nums++
}

pop

pop(){
    // 需要判断栈是否为空,为空返回undefined
    if(this.isNull()){
        return undefined
    }
    //因为push 方法最后会讲nums + 1,所以此处需要 -1 来保证nums的值对应栈的顶部
    this.nums--
    //定义一个变量保存栈顶元素
    const popData = this.items[this.nums]
    //删除栈顶元素
    delete this.items[this.nums]
    return popData
}

top

top(){
    // 需要判断栈是否为空,为空返回undefined
    if(this.isNull()){
        return undefined
    }
    //因为top方法不改变栈的元素,所以此处不必改变nums的值
    return this.items[this.nums - 1]
}

isNull

isNull(){
    return this.nums === 0
}

clear

clear(){
    this.items = {}
    this.nums = 0
}

size

size(){
    return this.nums
}

完整代码如下:

class Stack {
    constructor(){
        this.items = {}
        this.nums = 0
    }
    push(data){
        this.items[this.nums] = data
        this.nums++
    }
    pop(){
        if(this.isNull()){
            return undefined
        }
        this.nums--
        const popData = this.items[this.nums]
        delete this.items[this.nums]
        return popData
    }
    top(){
        if(this.isNull()){
            return undefined
        }
        return this.items[this.nums - 1]
    }
    isNull(){
        return this.nums === 0
    }
    clear(){
        this.items = {}
        this.nums = 0
    }
    size(){
        return this.nums
    }
}
const stack = new Stack()
console.log(stack.isNull()); //true
stack.push(1)
stack.push(2)
stack.push(3)
stack.push(4)
stack.push(5)
console.log(stack.size()); //5
console.log(stack.top());  //5
console.log(stack.pop());  //5
console.log(stack.top());  //4
console.log(stack.size()); //4
console.log(stack.isNull()); //false
stack.clear()
console.log(stack.isNull()); //true
console.log(stack.size()); //0

总结

让我们对两种实现方法做个比较。

const stark1 = new StackByArrar()
const stark2 = new StackByObject()
for(let i = 0;i < 100000000;i++){
    stark1.push(i)
}
for(let i = 0;i < 100000000;i++){
    stark2.push(i)
}

console.time('starkByArray')
stark1.push('123')
stark1.top()
stark1.pop()
stark1.size()
stark1.isNull()
console.timeEnd('starkByArray')
console.time('starkByObject')
stark2.push('123')
stark2.top()
stark2.pop()
stark2.size()
stark2.isNull()
console.timeEnd('starkByObject')

image.png

可以看到由于采用对象存储,对于对象的读取,时间复杂度为O(1),数据量过大时消耗时间也会比数组更短。

image.png

由于对象实现比数组多一个变量,数组由于是顺序存储,又比对象更占空间,从结果看,所占空间五五开。各位看官,你认为的对象存储是否是这样呢?评论区我们可以交流讨论。