JavaScript数据结构——队列(3)

140 阅读2分钟

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

前言

上次我们基于对象实现了一个队列类,本期我们来实现队列的进阶1——双端队列。按照惯例,我们先来介绍一下,什么是双端队列。

定义

deque(double-ended queue,双端队列)是一种具有队列的性质的数据结构。双端队列中的元素可以从两端弹出,相比list增加[]运算符重载

简单讲,双端队列就是队头和队尾皆能添加或移除数据的特殊队列。既然了解了什么是双端队列,那就看看他都有什么方法呢。

双端队列的方法

  • pushHead(): 向双端队列的队头添加元素
  • pushTail(): 向双端队列的队尾添加元素
  • popHead(): 从双端队列的头部移除元素
  • popTail(): 从双端队列的尾部移除元素
  • head(): 返回双端队列的队头元素,不改变队列
  • tail(): 返回双端队列的对尾元素,不改变队列
  • isNull(): 双端队列是否为空
  • clear(): 清空队列
  • size(): 返回队列大小

编码实现

创建类

class Deque{
    constructor(){
        //对象存储,由于对象是无序存储,所以需要辅助变量来优化结构
        this.items = {}
        //队尾指针
        this.end = 0
        //队头指针
        this.start = 0
    }
}

pushHead()

pushHead(data){
    //从双端队列的队头添加元素包含三种情况
    //1. 队列为空
    //2. start指针>=1,队头元素已经出队,则需要将队头指针减一并将新元素放在该键的位置上
    //3. start指针 = 0,未从队头出过队。

    //判断是否为空,为空则可以往队列后添加一个元素
    if(this.isNull()){
        // 情况1
        this.pushTail(data)
    }else if(this.start > 0){
        // 情况2
        this.start--
        this.items[this.start] = data
    }else{
        //情况3
        for(let i = this.end;i > 0 ;i--){
            //每位顺势后移一位,空出第一位
            this.items[i] = this.items[i - 1]
        }
        //队尾指针+1
        this.end++
        //第一位空闲,赋新值
        this.items[0] = data
    }
}

pushTail()

pushTail(data){
    this.items[this.end] = data
    this.end++
}

popHead()

popHead(){
    if(this.isNull()){
        return undefined
    }
    const result = this.items[this.start]
    delete this.items[this.start]
    this.start++
    return result
}

popTail()

popTail(){
    if(this.isNull()){
        return undefined
    }
    this.end--
    const popData = this.items[this.end]
    delete this.items[this.end]
    return popData
}

head()

head(){
    if(this.isNull()){
        return undefined
    }
    return this.items[this.start]
}

tail()

tail(){
    if(this.isNull()){
        return undefined
    }
    return this.items[this.end - 1]
}

isNull()

isNull(){
    return this.end - this.start === 0
}

clear()

clear(){
    this.items = {}
    this.end = 0
    this.start = 0
}

size()

size(){
    return this.end - this.start
}

完整代码

class Deque {
    constructor(){
        this.items = {}
        this.end = 0
        this.start = 0
    }
    pushHead(data){
        if(this.isNull()){
            this.pushTail(data)
        }else if(this.start > 0){
            this.start--
            this.items[this.start] = data
        }else{
            for(let i = this.end;i > 0 ;i--){
                this.items[i] = this.items[i - 1]
            }
            this.end++
            this.items[0] = data
        }
    }
    pushTail(data){
        this.items[this.end] = data
        this.end++
    }
    popHead(){
        if(this.isNull()){
            return undefined
        }
        const result = this.items[this.start]
        delete this.items[this.start]
        this.start++
        return result
    }
    popTail(){
        if(this.isNull()){
            return undefined
        }
        this.end--
        const popData = this.items[this.end]
        delete this.items[this.end]
        return popData
    }
    head(){
        if(this.isNull()){
            return undefined
        }
        return this.items[this.start]
    }
    tail(){
        if(this.isNull()){
            return undefined
        }
        return this.items[this.end - 1]
    }
    isNull(){
        return this.end - this.start === 0
    }
    clear(){
        this.items = {}
        this.end = 0
        this.start = 0
    }
    size(){
        return this.end - this.start
    }
}

const deque = new Deque()

console.log(deque.isNull());//true
deque.pushTail(2)
deque.pushTail(3)
deque.pushTail(4)
deque.pushTail(5)
deque.pushHead(1)
console.log(deque.isNull());//false
console.log(deque.size());//5
console.log(deque.head());//1
console.log(deque.tail());//5
console.log(deque.popHead());//1
console.log(deque.popTail());//5
console.log(deque.head());//2
console.log(deque.tail());//4
console.log(deque.size());//3
deque.clear()
console.log(deque.size());//0
console.log(deque.isNull());//true

总结

本次我们实现了双端队列,其很多方法与栈和队列相同,各位是这样实现的吗?有什么更好的思路欢迎评论区告诉我,下次我们实现进阶2——循环队列。