算法_设计循环队列(#622)

98 阅读3分钟

题目

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

来源:力扣(LeetCode) 链接:leetcode.cn/problems/de… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 image.png

题意概括:

一个数组(非循环),把它设计成循环的,如果是链表的话就是设计成一个圈。然后去补充队列为循环时,去写一些 队列为空、为满、插入、删除、头部值、尾部值的函数。

分析一波

因为为了为空为满时,方便,所以多给了一个空间,也就是说,当还剩一个空间的时候,那么这个队列就满了。

front: 表示队列的头部也就是第一个元素的下标。

rear:  表示队尾的下一个元素的下标。(即下一个从队尾入队元素的位置)。(当初困惑点)

k:  队列的总空间,也就是最多能容纳的数量。

cnt: 队列的长度。

当队列为空时: front===rear

当队列满时: (rear+1) % k===front. 还差一个元素空间的时候判定为满。 %一下是因为要取余,因为要设置成一个循环的,所以超过的部分就重新从头部数。(当初困惑点)

这个循环列表,它的某位置上的元素被删除,但是后面的添加进来的元素依旧可以去占位以及使用。

插入的话: 必须先要判断一下是为满,满的话就已插不进去了。

删除的话,就是head往后走一步,依旧是最先判断队列是否为空。是否头部删除。所以是head+1

因为rear表示的是队尾下一个元素的下标,所以在求队尾元素值的时候,要rear-1, 因为怕溢出,所以也要取余。 因此:(rear-1 + k)%k

注意点

这里为什么要+k?
因为:
如果rear在最开始的头部,那么它-1的话,那么它的下标就是-1,就出去了,
总不能给返回个-1求值吧, 必须得进入到圈内,
所以,
就需要rear -1 + k再去求余,如果rear不在最开始的头部而是个2,
然后总k是8,2-1+8=9,也会溢出,
所以求余,9%8=1
事实上rear为2的上一个也确实是1。

实践,上代码

/**
 * @param {number} k
 */
var MyCircularQueue = function (k) {
    this.queue = new Array(k + 1);
    this.head = 0;
    this.rear = 0;
    this.k = k+1;

};

/** 
 * @param {number} value
 * @return {boolean}
 */
MyCircularQueue.prototype.enQueue = function (value) {
    if (this.isFull()) return false;
    this.queue[this.rear] = value;
    // 这里rear有加1,还没等给queque里面去赋值,再次插入值的时候,先去判断是否为满,就会rear再次加1,这样就会始终少一个,导致不准确,错误的,所以多给一个空间的同时也要给k加一个1.
    this.rear = (this.rear + 1) % this.k;
    return true;
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.deQueue = function () {
    if (this.isEmpty()) return false;
    //没啥用了
    // this.cnt--;
    this.head = (this.head + 1) % this.k;
    return true;
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Front = function () {
    if (this.isEmpty()) return -1;
    return this.queue[this.head];
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Rear = function () {
    if (this.isEmpty()) return -1;
    console.log(this.queue);
    return this.queue[(this.rear - 1 + this.k) % this.k]

};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isEmpty = function () {
    return this.head === this.rear;
    //这是另外一种解法,也可行,如果这里不用这种那么前面的cnt计数也没啥用了,也节省了一个空间。
    // return this.cnt === 0;
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isFull = function () {
    return this.head === (this.rear + 1) % this.k;
     //这是另外一种解法,也可行,如果这里不用这种那么前面的cnt计数也没啥用了,也节省了一个空间。
    // return this.cnt===this.k;

};

this.rear = (this.rear + 1) % this.k;
这里rear有加1,还没等给queque里面去赋值,再次插入值的时候,先去判断是否为满,就会rear再次加1,这样就会始终少一个,导致不准确,错误的,所以多给一个空间的同时也要给k加一个1.