堆排序
堆其实就是一棵完全二叉树
小根堆向下调整函数如下:
function sift2(arr, low, high) {
//low表示当前需要调整的子树的根节点
//i表示的是当前的空位
let i = low;
//j表示当前子树的左孩子
let j = 2 * i + 1;
//缓存当前子树的根节点
let tmp = arr[low];
//如果左孩子小于或等于树的大小
while (j <= high) {
//判断当前节点的右孩子存不存在并且和左孩子比较大小
if (j + 1 <= high && arr[j + 1] < arr[j]) {
j = j + 1;
}
// 如果当前节点大于较小的那个孩子 就让较小的孩子到空位上去 然后空位下移
if (tmp > arr[j]) {
arr[i] = arr[j]
i = j;
j = 2 * i + 1;
} else {
break
}
}
//将刚开始要调整的那个节点放到空位上去
arr[i] = tmp;
}
function heapSort2(arr) {
let n = arr.length;
for (let i = (n - 2) >> 1; i >= 0; i--) {
sift2(arr, i, n - 1)
}
//挨个出数
for (let i = n - 1; i >= 0; i--) {
[arr[0], arr[i]] = [arr[i], arr[0]]
sift2(arr, 0, i - 1)
}
}
使用情况,TOPK问题
// TopK问题找前K大的数需要创建小根堆
function topk(arr, k) {
// 取前K个数创建小根堆
let heap = arr.slice(0, k)
for (let i = (k - 2) >> 1; i >= 0; i--) {
sift2(heap, i, k - 1)
}
// 创建小根堆
// 用后面的数和堆顶的数比较如果后面的数大那么就替换掉堆顶的元素并且向下调整一次使得堆顶元素最小
for (let j = k; j < arr.length; j++) {
if (arr[j] > heap[0]) {
heap[0] = arr[j];
sift2(heap, 0, k - 1)
}
}
// 至此前K大的数已经就绪就在heap数组中,但是不是按照顺序排列的
// 挨个出数来保证前K大的数挨个排列
for (let i = k - 1; i >= 0; i--) {
[heap[0], heap[i]] = [heap[i], heap[0]]
sift2(heap, 0, i - 1)
}
return heap
}