设计循环队列

86 阅读4分钟

这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

问题描述

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

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

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

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

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

提示:

  • 所有的值都在 0 至 1000 的范围内;
  • 操作数将在 1 至 1000 的范围内;
  • 请不要使用内置的队列库。

思路分析

首先我们先要理解一下题目意思,题目会要求我们设计一个循环队列的数据结构,需要具备以下几个功能:

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

我们先来分别分析一下每一个功能的具体实现思路

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。

传入参数k,并构造一个容量为k的循环队列,我们需要记录循环队列的头结点、尾结点、队列长度及队列元素,具体初始化代码如下:

/**
 * @param {number} k
 */
var MyCircularQueue = function (k) {
  this.list = new Array(k).fill(-1);
  this.size = k;
  this.head = 0;
  this.tail = -1;
};
  • Front: 从队首获取元素。如果队列为空,返回 -1 。

调用Front方法可以获取当前循环队列的头结点元素,初始化时我们已经有一个变量用于存放当前队列的头结点下标,直接将头结点元素返回即可,具体代码如下:

/**
 * @return {number}
 */
MyCircularQueue.prototype.Front = function () {
  return this.list[this.head];
};
  • Rear: 获取队尾元素。如果队列为空,返回 -1 。

调用Rear方法可以获取当前循环队列的尾结点元素,初始化时我们已经有一个变量用于存放当前队列的尾结点下标,直接将尾结点元素返回即可,具体代码如下:

/**
 * @return {number}
 */
MyCircularQueue.prototype.Rear = function () {
  return this.list[this.tail] == undefined ? -1 : this.list[this.tail];
};
  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

调用enQueue方法在循环队列尾部插入一个元素,插入前需要先判断队列是否已满,已满的话则无法继续插入元素,否则则将元素插入,并更新当前队列的尾结点下标值,具体代码如下:

/**
 * @param {number} value
 * @return {boolean}
 */
MyCircularQueue.prototype.enQueue = function (value) {
  if (this.isFull()) return false;
  this.tail = (this.tail + 1) % this.size;
  this.list[this.tail] = value;
  return true;
};
  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

调用deQueue方法在循环队列头部删除一个元素,删除前需要先判断队列是否为空,为空的话则无法删除元素,否则则将头部元素删除,并更新当前队列的头结点下标值,具体代码如下:

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.deQueue = function () {
  if (this.isEmpty()) return false;
  this.list[this.head] = -1;
  this.head = (this.head + 1) % this.size;
  return true;
};
  • isEmpty(): 检查循环队列是否为空。

调用isEmpty方法,检查循环队列是否为空,我们则需要判断队列的头结点是否有值即可,具体代码如下:

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isEmpty = function () {
  return this.list[this.head] == -1;
};
  • isFull(): 检查循环队列是否已满。

调用isFull方法,检查循环队列是否已满,我们则需要判断队列尾结点的下一节点是否有值即可,具体代码如下:

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isFull = function () {
  const ind = (this.tail + 1) % this.size;
  return this.list[ind] != -1;
};

完整 AC 代码如下:

AC 代码

/**
 * @param {number} k
 */
var MyCircularQueue = function (k) {
  this.list = new Array(k).fill(-1);
  this.size = k;
  this.head = 0;
  this.tail = -1;
};

/**
 * @param {number} value
 * @return {boolean}
 */
MyCircularQueue.prototype.enQueue = function (value) {
  if (this.isFull()) return false;
  this.tail = (this.tail + 1) % this.size;
  this.list[this.tail] = value;
  return true;
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.deQueue = function () {
  if (this.isEmpty()) return false;
  this.list[this.head] = -1;
  this.head = (this.head + 1) % this.size;
  return true;
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Front = function () {
  return this.list[this.head];
};

/**
 * @return {number}
 */
MyCircularQueue.prototype.Rear = function () {
  return this.list[this.tail] == undefined ? -1 : this.list[this.tail];
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isEmpty = function () {
  return this.list[this.head] == -1;
};

/**
 * @return {boolean}
 */
MyCircularQueue.prototype.isFull = function () {
  const ind = (this.tail + 1) % this.size;
  return this.list[ind] != -1;
};

/**
 * Your MyCircularQueue object will be instantiated and called as such:
 * var obj = new MyCircularQueue(k)
 * var param_1 = obj.enQueue(value)
 * var param_2 = obj.deQueue()
 * var param_3 = obj.Front()
 * var param_4 = obj.Rear()
 * var param_5 = obj.isEmpty()
 * var param_6 = obj.isFull()
 */

说在后面

大家好,这里是葛藟,本人为算法业余爱好者,平时只是随着兴趣偶尔刷刷题,如果上面分享有错误的地方,欢迎指出,感激不尽。