一起养成写作习惯!这是我参与「掘金日新计划 · 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——循环队列。