Skip to content

循环队列

普通队列中出队的操作时间复杂度为 O(n),因为每出队一个元素,都需要将其他所有的元素往前挪动。假设数组中有 100 万个元素,则每次出队都需要进行 100 万次的操作,这种时间花费是比较大的。

而使用循环队列,则可以解决普通队列出队操作时间复杂对为 O(n)的问题。

循环队列接口:

typescript
interface LoopQueueInterface<T> {
  size: number
  isEmpty: boolean
  capacity: number

  enqueue: (element: T) => void
  dequeue: () => T | undefined
  getFront: () => T | undefined
  clear: () => void
}

循环队列具体实现:

typescript
class LoopQueue<T> implements LoopQueueInterface<T> {
  #data: T[]
  #front: number
  #tail: number
  #size: number
  #initialCapacity: number

  constructor(capacity: number = 10) {
    this.#data = new Array(capacity)
    this.#front = 0
    this.#tail = 0
    this.#size = 0
    this.#initialCapacity = capacity
  }

  get isEmpty() {
    return this.#size === 0
  }

  get capacity() {
    return this.#data.length
  }

  get size() {
    return this.#size
  }

  #resize(newCapacity: number) {
    const newData = new Array(newCapacity)

    for (let i = 0; i < this.#size; i++) {
      newData[i] = this.#data[(i + this.#front) % this.#data.length]
    }

    this.#front = 0
    this.#tail = this.#size

    this.#data = newData
  }

  enqueue(element: T) {
    if (this.#size === this.capacity) {
      this.#resize(this.capacity * 2)
    }

    this.#data[this.#tail] = element
    this.#tail = (this.#tail + 1) % this.#data.length
    this.#size++
  }

  dequeue() {
    if (this.isEmpty) {
      return undefined
    }

    const result = this.#data[this.#front]
    this.#front = (this.#front + 1) % this.#data.length
    this.#size--

    if (this.#size === Math.floor(this.capacity / 4) && Math.floor(this.capacity / 2) !== 0) {
      this.#resize(this.capacity / 2)
    }

    return result
  }

  getFront() {
    if (this.isEmpty) {
      return undefined
    }

    return this.#data[this.#front]
  }

  clear() {
    this.#data = new Array(this.#initialCapacity)
    this.#front = 0
    this.#tail = 0
    this.#size = 0
  }
}

使用 Deque 实现

Deque 内部其实也是使用 LoopQueue 实现,Deque 的接口会比 LoopQueue 丰富一些。

typescript
class LoopQueue<T> implements LoopQueueInterface<T> {
  deque: Deque<T>

  constructor(capacity: number = 10) {
    this.deque = new Deque({
      capacity,
      autoShrink: true,
    })
  }

  get isEmpty() {
    return this.deque.isEmpty
  }

  get capacity() {
    return this.deque.capacity
  }

  get size() {
    return this.deque.size
  }

  enqueue(element: T) {
    this.deque.addLast(element)
  }

  dequeue() {
    return this.deque.removeFirst()
  }

  getFront() {
    return this.deque.peekFirst()
  }

  clear() {
    this.deque.clear()
  }
}