设计循环队列

解题思路

队列是遵行先进先出的策略,而循环队列则使用固定大小的数组,使得队列在数组未空的情况下,绕行数组添加元素或删除元素,采用双指针来指示不断变化的头部与尾部,目的是未了节省内存的空间。

代码

class MyCircularQueue {
  queue: number[]; // 数组
  length: number; // 数组长度
  header: number = -1; // 初始化指针,头部
  tail: number = -1; // 初始化指针,尾部

  constructor(k: number) {
    // 初始化队列的长度,并以undefined进行空填充
    this.queue = new Array(k); 
    this.length = k;
  }

  // 在尾部添加一个元素
  enQueue(value: number): boolean {
    // 判断数组是否已满
    if (this.isFull()) {
      return false;
    }
    // 当头部的指针与尾部的指针都是-1,表示两指针第一次步进1
    if (this.header === -1 && this.tail === -1) {
      this.header += 1;
      this.tail += 1;
    } else {
      this.tail += 1;
      // 由于是循环队列,尾部指针的最大值不能超过数组的最大索引值,当超过最大索引值,需要重新指向0
      this.tail = this.tail % this.length;
    }
    // 赋值永远在尾部
    this.queue[this.tail] = value;
    return true;
  }

  // 在头部删除一个元素
  deQueue(): boolean {
    // 如果数组为空,则必会删除失败
    if (this.isEmpty()) {
      return false;
    }
    // 删除动作永远在头部指针上
    delete this.queue[this.header];
    // 删除后需要将头部指针步进1
    this.header += 1;
    // 同理,循环队列的头部指针与尾部指针都需要循环绕行,不能大于最大索引值
    this.header = this.header % this.length;
    return true;
  }

  // 返回头部元素
  Front(): number {
    const empty = this.isEmpty();
    if (empty) {
      return -1;
    }
    return this.queue[this.header];
  }

  // 返回尾部元素
  Rear(): number {
    const empty = this.isEmpty();
    if (empty) {
      return -1;
    }
    return this.queue[this.tail];
  }

  // 是否为空
  isEmpty(): boolean {
    // 初始化 结果为空
    let result = true;
    // 当发现一个元素不为空,则此数组必不为空,跳出循环
    for (let i = 0; i < this.queue.length; i++) {
      if (this.queue[i] !== undefined) {
        result = false;
        break;
      }
    }
    return result;
  }

  // 是否已满
  isFull(): boolean {
    // 初始化 结果为满
    let result = true;
    // 当发现一个元素为空,则此数组必然未满,跳出循环
    for (let i = 0; i < this.queue.length; i++) {
      if (this.queue[i] === undefined) {
        result = false;
        break;
      }
    }
    return result;
  }
}