一、前置知识
1.1 队列
队列是一种操作受限制的线性表,其特点是先进先出,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作
1.2 队列缺点
不能利用有效空间,执行删除操作后,会清理一些内存空间出来,但是,由于只能在队尾插入,故前面清理出的空间就不能有效利用了。
但是环形队列可以解决这个问题,把队列空间想象成一个环形空间,环形空间中的存储单元循环使用。
1.3 环形队列
无论插入或删除操作,一旦rear指针增1或者front指针增1超出了所分配的队列空间,就让它指向这篇连续空间的起始位置。
环形链表又被称为环形缓冲器。
二、题目描述
看完基础知识,我们来看下题目描述,具体需要实现什么:
- MyCircularQueue(k): 构造器,设置队列长度为 k
- Front: 从队首获取元素。如果队列为空,返回 -1
- Rear: 获取队尾元素。如果队列为空,返回 -1
- enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真
- deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真
- isEmpty(): 检查循环队列是否为空
- isFull(): 检查循环队列是否已满 若想要看更详细的操作,请看leetcode题目链接
三、解题
3.1 具体实现
3.1.1 构造器,设置队列长度为 k
用来创建环形队列实例,环形队列需创建时知道 队列,front指针,rear指针,队列最大容量。
var MyCircularQueue = function (k) {
this.front = 0
this.rear = 0
this.max = k
this.queue = new Array(k).fill(null)
}
3.1.2 检查队列是否为空
判空的条件很简单,其实就是front、rear指针指向同一元素,该元素为null
MyCircularQueue.prototype.isEmpty = function () {
return (this.front === this.rear) && (this.queue[this.front] === null)
}
3.1.3 检查循环队列是否已满
判空的条件很简单,其实就是front、rear指针指向同一元素,该元素不为null
MyCircularQueue.prototype.isEmpty = function () {
return (this.front === this.rear) && (this.queue[this.front] !== null)
}
3.1.4 从队首获取元素。如果队列为空,返回 -1
先判空,判空则返回-1
MyCircularQueue.prototype.Front = function () {
if(this.isEmpty()) return -1
return this.queue[this.front]
}
3.1.5 获取队尾元素。如果队列为空,返回 -1
先判空,判空则返回-1。这里rear需要注意,这个指针队列尾元素的后一位
MyCircularQueue.prototype.Rear = function () {
if(this.isEmpty()) return -1
return this.queue[this.rear === 0 ? this.max - 1 : this.rear - 1 ]
}
3.1.6 向循环队列插入一个元素。如果成功插入则返回真
注意指针后移时取余
MyCircularQueue.prototype.enQueue = function(value) {
// 判满返回false
if(this.isFull()) return false
// 先往队尾添加
this.queue[this.rear] = value
// 尾指针后移: 这个环有点像取余,比如队列长7,尾指针到了队尾,再加就是 (7+1) % 7
this.rear = (this.rear + 1) % this.max
return true
};
3.1.7 从循环队列中删除一个元素。如果成功删除则返回真
注意指针后移时取余
MyCircularQueue.prototype.deQueue = function() {
// 判空返回false
if(this.isEmpty()) return false
// 队头出队
this.queue[this.front] = null
// 头指针后移
this.front = (this.front + 1) % this.max
return true
};
3.2 整体代码
/**
* @param {number} k
*/
var MyCircularQueue = function(k) {
// 头指针
this.front = 0
// 尾指针
this.rear = 0
// 队列长度
this.max = k
// 队列
this.queue = Array(k).fill(null)
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularQueue.prototype.enQueue = function(value) {
// 判满返回false
if(this.isFull()) return false
// 先往队尾添加
this.queue[this.rear] = value
// 尾指针后移: 这个环有点像取余,比如队列长7,尾指针到了队尾,再加就是 (7+1) % 7
this.rear = (this.rear + 1) % this.max
return true
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.deQueue = function() {
// 判空返回false
if(this.isEmpty()) return false
// 队头出队
this.queue[this.front] = null
// 头指针后移
this.front = (this.front + 1) % this.max
return true
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Front = function() {
// 队列为空,返回-1
if(this.isEmpty()) return -1
return this.queue[this.front]
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Rear = function() {
// 队列为空,返回-1
if(this.isEmpty()) return -1
return this.queue[this.rear === 0 ? this.max -1 : this.rear - 1]
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isEmpty = function() {
// 头指针、尾指针同时指向一个元素,且该元素为null
return (this.front === this.rear) && (this.queue[this.front] === null)
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isFull = function() {
// 头指针、尾指针同时指向一个元素,且该元素不为null
return (this.front === this.rear) && (this.queue[this.front] !== null)
};