大纲
- 堆尾添加节点功能
 - 弹出堆顶节点功能
 - 自顶向下排序功能
 - 自下向顶排序功能
 - 元素大小比较函数
预览
```javascript /**- 例如小顶堆堆:
 - 1
 - 3 5
 - 4 6 8 10
 - 数组化: [1, 3, 5, 4, 6, 8, 10];
 - */
 
 
/**
- 取出堆顶[1]
 - ?
 - 3 5
 - 4 6 8 10
 - 数组化: [, 3, 5, 4, 6, 8, 10];
 - 将堆尾的节点放入堆顶,然后自顶向下排序
 - 10
 - 3 5
 - 4 6 8
 - 数组化: [10, 3, 5, 4, 6, 8];
*/
<a name="IK8Bw"></a>### compare```javascriptfunction compare(a, b) {return a - b;}
siftDown(自顶向下排序)
```javascript /** - 将堆尾的节点放入堆顶,然后自顶向下排序
 - 10
 - 3 5
 - 4 6 8
 - 数组化: [10, 3, 5, 4, 6, 8]; *
 - 数组长度为6, 只要下个遍历的父节点 大于或者等于 数组的一半,就代表没有子节点,可以结束遍历
 - 左子节点: (当前父节点 + 1) * 2 - 1;
 - 假如父节点下标是0,左节点的位置就是 1, 3, 7, 15, 31, 63…
 - 可以发现的规律, 父节点的左子节点,一定是 父节点下标 * 2 + 1
 leftIdnex = (x << 1) + 1
父节点的右子节点就是左节点 + 1 *
- 当每次比较完父节点跟子节点的大小时
 - 假如 下标0的元素是(10), 左子节点下标1的元素是(3),右子节点下标2的元素是(5)
 - 比较三个数,下标1的元素(3)最小,将它放入下标0的父节点,将下标0的父节点放入下标1
 - 3
 - 10 5
 - 4 6 8
 - 此时 下一个比较的父节点应该是下标1的元素10
 - 因为它的节点发生了变化,需要重新比较它的左右子节点 *
 - 比较完堆的最后一个父节点的时候,这个堆就已经最小化完成了 */
 
/**
- @summary堆顶开始比较每个节点的左右子节点与父节点的大小
 - @param heap 堆
 - @param node 节点元素
 - @param i 当前父节点
 - @return {void}
*/
function siftDown(
i, ) {heap,node,
while(parentIndex < halfLength) {let parentIndex = i;let length = heap.length;let halfLength = length >>> 1;
} ```const leftIndex = (parentIndex << 1) + 1;const left = heap[leftIndex];const rightIndex = leftIndex + 1;const right = heap[rightIndex];// 进入到这一步,一定是有左子节点的,因为parentIndex < 堆一半的长度才能进循环if (compare(left, node) < 0) {if (rightIndex < length && compare(right, left) < 0) {heap[parentIndex] = right;heap[rightIndex] = node;parentIndex = rightIndex;} else {heap[parentIndex] = left;heap[leftIndex] = node;parentIndex = leftIndex;}} else if (rightIndex < length && compare(right, node) < 0) {heap[parentIndex] = right;heap[rightIndex] = node;parentIndex = rightIndex;} else {return;}}
siftUp(自下向顶排序)
```javascript /** - 向堆尾添加一个节点,然后自下向顶排序
 - 2
 - 3 10
 - 4 6 8 1
 - 数组化: [2, 3, 10, 4, 6, 8, 1]; *
 - 先查找到当前添加的节点下标的父节点
 - 下标6的父节点下标是2,下标5的父节点下标是2,下标4的父节点下标是1,….
 - 6 -> 2, 5 -> 2, 4 -> 1, 3 -> 1, 2-> 0, 1 -> 0
 - 有上面的规律可得当前下标的父节点计算方式为 ((子节点 - 1) / 2)向下取整
 - parentIndex = (x - 1) >>> 1; *
 - 当每次比较完父节点跟子节点的大小时
 - 假如 当前堆尾添加了下标为6的元素(1),父节点下标2的元素(10)
 - 2
 - 3 10
 - 4 6 8 1
 - 比较两个元素,下标6比下标2的元素小,交换两个下标的元素,并且将下个比较的下标置为这个下标2
 - 2
 - 3 1
 - 4 6 8 10
 - 下标为2的元素(2),父节点下标0的元素(1),进行比较,得到
 - 1
 - 3 2
 - 4 6 8 10
 - 此时下标为0,表示整个堆都已经最小化完成,并且实例图也表现一致 */
 
/**
- @summary堆顶开始比较每个节点的左右子节点与父节点的大小
 - @param heap 堆
 - @param node 节点元素
 - @param i 当前添加的节点下标
 - @return {void}
*/
function siftUp(
i, ) {heap,node,
while(index > 0) {let index = i;
}const parentIndex = (index - 1) >>> 1;const parent = heap[parentIndex];if (compare(parent, node) > 0) {heap[parentIndex] = node;heap[index] = parent;index = parentIndex;} else {return;}
}<a name="kg5k9"></a>### push(堆尾添加节点)```javascriptfunction push(heap, node) {// 当前的堆长度,就是节点的下标const index = heap.length;// 推入堆尾heap.push(node);// 自下向顶排序siftUp(heap, node, index);}
pop(堆顶弹出节点)
function pop(heap) {if (heap.length === 0) {return null;}// 拿出堆顶的节点const first = heap[0];// 弹出堆尾的节点const last = heap.pop();// 如果两个元素不相等,这个堆至少两个元素if (first !== last) {// 将堆尾元素放入堆顶heap[0] = last;// 自顶向下比较,最小堆化siftDown(heap, last, 0);}return first;}
 
