# 优先队列 js 写法
 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。
而在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出的行为特征。实际上采用的是二叉堆的形式进行存储。由于 js 没有提供现成的优先队列,所以记录一下其 js 的实现过程。
# 思路:
	对于一个完全二叉树来说,一个节点的编号为 i (从 0 开始计算),则其父节点的编号为 Math.floor((i-1)/2 , 其左右子节点的编号为 2*i+1 、 2*i+2 。此外对于一个堆来说最重要的就是插入和删除操作。
# 插入
举个例子,假如要在下面的二叉堆(小顶堆)中,再插入 2:

首先现在最后插入节点 2

然后因为 2 小于 5,不满足堆的性质,上浮

然后因为 2 小于 3,不满足堆的性质,继续上浮。最后到顶

# 删除
 删除与插入相反,删除的是堆顶元素,我们需要找到一个元素来替代堆顶的位置,以保证堆的性质不被破坏。因此进行如下的操作:
还是以前面建立的二叉堆为例,假如要删除堆顶的 2。则直接先把 2 删除,那么 2 的位置就有一个空穴。

然后将 5 替换到空穴的位置,然后因为 5>4>3 不满足小顶堆的性质,所以将 5 和 3 交换。

# 代码
| class PriorityQueue { | |
| constructor(sortBy) { | |
|     // 先把排序方式定下来, 默认值是按从小到大排序 | |
| this.sortBy = sortBy || ((a, b) => a - b); | |
|     // 一开始队列的样子,js 中用数组直接表示 | |
| this.queue = []; | |
|   } | |
| siftUp(index) { | |
| while (true) { | |
| let parentIndex = Math.floor((index - 1) / 2); | |
| console.log("当前", index, "父", parent); | |
|       // 进行上浮 | |
| if (this.sortBy(this.queue[index], this.queue[parentIndex]) < 0) { | |
| this.swap(index, parentIndex); | |
| index=parentIndex; | |
| } else { | |
|         // 终止 | |
| return; | |
|       } | |
|     } | |
|   } | |
| siftDown(i) { | |
| let left = i * 2 + 1; | |
| let right = i * 2 + 2; | |
| while (true) { | |
| let maxIndex = i; | |
|       // 左节点是最值的话 | |
| if ( | |
| left <= this.size() && | |
| this.sortBy(this.queue[left], this.queue[maxIndex]) < 0 | |
| ) { | |
| maxIndex = left; | |
|       } | |
|       // 右节点是最值的话 | |
| if ( | |
| right <= this.size() && | |
| this.sortBy(this.queue[right], this.queue[maxIndex]) < 0 | |
| ) { | |
| maxIndex = right; | |
|       } | |
|       // 如果当前节点不是最值,那么当前节点的值要往下传递,让下面的最值冒泡上来 | |
| if (maxIndex !== i) { | |
| this.swap(i, maxIndex); | |
| this.siftDown(maxIndex); | |
| } else { | |
| return; | |
|       } | |
|     } | |
|   } | |
|   // 入队 -- 插入元素 | |
| enQueue(node) { | |
| this.queue.push(node); | |
| this.siftUp(this.size() - 1); | |
| this.print(); | |
|   } | |
| print() { | |
| console.log(this.queue); | |
|   } | |
|   // 出队 -- 获取最值 | |
| deQueue() { | |
| const top = this.front(); | |
| this.queue[0] = this.queue.pop(); | |
| this.siftDown(0); | |
|   } | |
|   // 获取最值 -- 不移除 | |
| front() { | |
| return this.queue[0]; | |
|   } | |
|   // 获取队列中的元素总数 | |
| size() { | |
| return this.queue.length; | |
|   } | |
|   // 判断当前优先队列是否为空 | |
| isEmpty() { | |
| return this.size() === 0; | |
|   } | |
|   // 清空当前队列中的所有元素 | |
| clear() { | |
| this.queue = []; | |
|   } | |
|   // 交换节点的值 | |
| swap(i, j) { | |
| const temp = this.queue[i]; | |
| this.queue[i] = this.queue[j]; | |
| this.queue[j] = temp; | |
|   } | |
| } | |
| queue = new PriorityQueue(); | 
演示地址:https://codepen.io/memoryoflove/pen/jOaeVxY
