返回
从头理解 JavaScript 数据结构与算法:优先队列
前端
2023-12-28 12:11:40
在现实世界中,我们经常会遇到优先排队的情况,例如买票、结账或使用公共设施时,特殊情况(如紧急状况)的人可以优先处理。这种机制被称为优先队列。它不同于普通队列,因为每个元素不仅是一个数据,还包括一个优先级。在添加元素的过程中,根据优先级将其插入到队列中的正确位置。
优先队列的工作原理
优先队列是一个抽象数据类型,它支持以下基本操作:
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* 搜索算法,根据优先级对候选路径进行排序。