返回

从头理解 JavaScript 数据结构与算法:优先队列

前端

在现实世界中,我们经常会遇到优先排队的情况,例如买票、结账或使用公共设施时,特殊情况(如紧急状况)的人可以优先处理。这种机制被称为优先队列。它不同于普通队列,因为每个元素不仅是一个数据,还包括一个优先级。在添加元素的过程中,根据优先级将其插入到队列中的正确位置。

优先队列的工作原理

优先队列是一个抽象数据类型,它支持以下基本操作:

  • insert(element, priority):向队列中添加一个元素,并指定其优先级。
  • extractMin():从队列中删除并返回优先级最低的元素。
  • peekMin():返回队列中优先级最低的元素,但不将其删除。

优先队列通常使用二叉堆数据结构实现,它是一个完全二叉树,其中每个节点的优先级都小于或等于其子节点的优先级。这允许我们有效地进行插入、删除和查找最小元素的操作。

JavaScript 中的优先队列

JavaScript 没有内置的优先队列数据结构,但可以使用堆或二叉搜索树来实现。下面是一个使用二叉堆实现的优先队列:

class PriorityQueue {
  constructor() {
    this.heap = [];
  }

  insert(element, priority) {
    this.heap.push({ element, priority });
    this.heapifyUp();
  }

  extractMin() {
    if (this.heap.length === 0) {
      return null;
    }
    const min = this.heap[0];
    this.heap[0] = this.heap[this.heap.length - 1];
    this.heap.pop();
    this.heapifyDown();
    return min.element;
  }

  peekMin() {
    if (this.heap.length === 0) {
      return null;
    }
    return this.heap[0].element;
  }

  heapifyUp() {
    let index = this.heap.length - 1;
    while (index > 0) {
      const parentIndex = Math.floor((index - 1) / 2);
      if (this.heap[index].priority < this.heap[parentIndex].priority) {
        this.swap(index, parentIndex);
        index = parentIndex;
      } else {
        break;
      }
    }
  }

  heapifyDown() {
    let index = 0;
    while (index < this.heap.length) {
      const leftIndex = 2 * index + 1;
      const rightIndex = 2 * index + 2;
      let smallestIndex = index;
      if (leftIndex < this.heap.length && this.heap[leftIndex].priority < this.heap[smallestIndex].priority) {
        smallestIndex = leftIndex;
      }
      if (rightIndex < this.heap.length && this.heap[rightIndex].priority < this.heap[smallestIndex].priority) {
        smallestIndex = rightIndex;
      }
      if (smallestIndex !== index) {
        this.swap(index, smallestIndex);
        index = smallestIndex;
      } else {
        break;
      }
    }
  }

  swap(index1, index2) {
    const temp = this.heap[index1];
    this.heap[index1] = this.heap[index2];
    this.heap[index2] = temp;
  }
}

使用优先队列

优先队列广泛应用于各种场景,例如:

  • 事件处理: 根据优先级处理事件,确保最紧急的事件得到最快的响应。
  • 资源分配: 将有限的资源分配给优先级最高的请求。
  • 搜索算法: 例如 A* 搜索算法,根据优先级对候选路径进行排序。