设计循环队列

250 阅读4分钟

要求

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

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

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。 Front: 从队首获取元素。如果队列为空,返回 -1 。 Rear: 获取队尾元素。如果队列为空,返回 -1 。 enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。 deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。 isEmpty(): 检查循环队列是否为空。 isFull(): 检查循环队列是否已满。

思路

假设队列长度k=4

定义一个长度为k+1的数组let Queue = Array(k+1)

1.png

定义头指针front与尾指针rear,以及k的值max

当向数组内添加元素:rear+1,删除元素:front+1

2.png

3.png

Front: 从队首获取元素。如果队列为空,返回 -1 。

先判断队列是否为空:this.isEmpty()

为truereturn -1

为falsereturn this.Queue[this.front]

Rear: 获取队尾元素。如果队列为空,返回 -1 。

先判断队列是否为空:this.isEmpty()

为truereturn -1

为falsereturn this.Queue[this.rear - 1]

尾指针的值 - 1 就是最后队尾元素的下标,但是有可能出现下图情况

4.png

所以我们需要加上数组的最大长度k+1max+1,然后进行求余

即:(this.rear(0) - 1 + this.max(4) + 1) % (this.max(4) + 1)得到4,即上图的最后一个节点的1

enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

先判断队列是否为满:this.isEmpty()

为truereturn false

为false

  1. 插入元素到最后一个节点:this.Queue[this.rear] = value

  2. rear指针向后移动一步:this.rear += 1,但是要记得求余数组的最大长度,不然rear的数会超过数组的最大长度,所以应该this.rear = (this.rear + 1 + this.max + 1) % (this.max + 1)

  3. return true 告诉我们添加成功

deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

先判断队列是否为空:this.isEmpty()

为truereturn false

为false移动头指针即可this.front+=1,不过也需求余,即this.front = (this.front + 1) % (this.max + 1)

isEmpty(): 检查循环队列是否为空。

检查是否为空,判断两个指针的值即可

所以我们只需判断this.rear - this.front是否为0

所以我们return this.rear - this.front == 0;即可

因为两指针唯一一次重合的情况,就是一个值都没有的情况

isFull(): 检查循环队列是否已满。

检查是否已满,判断两指针相差是否为k即可

即判断this.rear - this.front == this.max是否为true

但是有可能rear的值比front的值要小,即下图情况

6.png

所以我们需要求余

(this.rear - this.front + this.max + 1) % (this.max + 1)

上图数据套入此计算中得出3,距离数组能存的最大值k(4)还差1,所以我们返回false

完整代码


var MyCircularQueue = function (k) {
    // 定义一个数组
    this.Queue = Array(k + 1);
    // 创建一个头指针,一个尾指针
    this.front = 0;
    this.rear = 0;
    // 数组最大容量
    this.max = k;
};

/** 
 * @param {number} value
 * @return {boolean}
 */
MyCircularQueue.prototype.enQueue = function (value) {
    // 先判断是否已满
    if (this.isFull()) return false;
    // 添加元素
    this.Queue[this.rear] = value;
    // 尾指针往后走一步
    this.rear = (this.rear + 1) % (this.max + 1);
    return true;
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.deQueue = function () {
    // 先判断是否为空
    if (this.isEmpty()) return false;
    // 头指针往后走一步即可删除
    this.front = (this.front + 1) % (this.max + 1)
    return true
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Front = function () {
    // 先判断是否为空
    if (this.isEmpty()) return -1;
    // 返回头指针的下标,就是第一个元素
    return this.Queue[this.front];
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Rear = function () {
    // 先判断是否为空
    if (this.isEmpty()) return -1;
    // 返回尾指针的下标-1的值,就是最后一个元素
    return this.Queue[(this.rear - 1 + this.max + 1) % (this.max + 1)];
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isEmpty = function () {
    // 判断头指针与尾指针的下标是否一致,一致,即数组为空
    return this.rear - this.front == 0;
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isFull = function () {
    // 尾指针减头指针,得到的数是否等于k值,若等于k值,即数组已满
    // 但尾指针有可能小于头指针,所以需要求余
    return ((this.rear - this.front + this.max + 1) % (this.max + 1)) == this.max;
};