Skip to content

双端队列

特点:

  • 可以在队列的两端添加元素
  • 可以在队列的两端删除元素

双端队列的灵活性可用于实现栈、队列、循环队列等数据结构。

双端队列接口设计:

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

  addFirst: (element: T) => void
  addLast: (element: T) => void

  removeFirst: () => T | undefined
  removeLast: () => T | undefined

  peekFirst: () => T | undefined
  peekLast: () => T | undefined

  clear: () => void
}

双端队列具体实现:

typescript
class Deque<T> implements DequeInterface<T> {
  #data: T[]
  #front = 0
  #size = 0
  #autoShrink: boolean

  constructor(options?: { capacity?: number; autoShrink?: boolean }) {
    const { capacity = 10, autoShrink = false } = options || {}

    this.#data = new Array(capacity)
    this.#autoShrink = autoShrink
  }

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

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

  get tail() {
    return this.getSafeIndex(this.#front + this.#size - 1)
  }

  get size() {
    return this.#size
  }

  private getSafeIndex(index: number) {
    return (index + this.capacity) % this.capacity
  }

  #resize(capacity: number) {
    const newData = new Array<T>(capacity)

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

    this.#data = newData
    this.#front = 0
  }

  #halfCapacity() {
    if (!this.#autoShrink) return

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

  #doubleCapacity() {
    if (this.size === this.capacity) {
      this.#resize(this.capacity * 2)
    }
  }

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

    // new element will be added to the (this.front -1) position
    this.#front = this.getSafeIndex(this.#front - 1)
    this.#data[this.#front] = element
    this.#size++

    this.#doubleCapacity()
  }

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

    // new element will be added to the (this.tail + 1) position
    this.#data[this.getSafeIndex(this.tail + 1)] = element
    this.#size++

    this.#doubleCapacity()
  }

  removeFirst(): T | undefined {
    if (this.isEmpty) {
      return undefined
    }

    const result: T = this.#data[this.#front]
    this.#front = this.getSafeIndex(this.#front + 1)
    this.#size--

    this.#halfCapacity()

    return result
  }

  removeLast(): T | undefined {
    if (this.isEmpty) {
      return undefined
    }

    const result = this.#data[this.tail]
    this.#size--

    this.#halfCapacity()

    return result
  }

  peekFirst(): T | undefined {
    if (this.isEmpty) {
      return undefined
    }
    return this.#data[this.#front]
  }

  peekLast(): T | undefined {
    if (this.isEmpty) {
      return undefined
    }

    return this.#data[this.tail]
  }

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