每个父节点都小于他的左,右,孩子节点的值,最小堆
var count = 0;
function up_adjust (arr) { // 下沉操作
let childIndex = arr.length - 1;
// 取余二等于零 就是一个右孩子
let parentIndex = childIndex - 1;
let temp = arr[childIndex];
while (childIndex > 0 && temp < arr[parentIndex]) {
count++;
// 子元素存在 并且 子元素小于父元素
// 父元素下沉
arr[childIndex] = arr[parentIndex];
childIndex = parentIndex;
parentIndex = childIndex - 1;
}
// 子元素上浮
arr[childIndex] = temp;
}
function down_adjust(parentIndex, len, arr) { // 上浮操作
// parentIndex 待下沉目标
// len 堆的长度范围
// arr 二叉堆数组
let temp = arr[parentIndex];
let childIndex = 2 * parentIndex + 1; // 左孩子
while (childIndex < len) {
count++;
if (childIndex + 1 < len && arr[childIndex + 1] < arr[childIndex]) {
// 右孩子存在,并且右孩子小于左孩子
childIndex += 1;
}
if (temp <= arr[childIndex]) {
// 父节点小于任何一个孩子的值,直接跳出
break;
}
// 父元素下沉,子元素上浮
arr[parentIndex] = arr[childIndex];
parentIndex = childIndex;
childIndex = 2 * childIndex + 1; // 左孩子的下标
}
// 子元素上浮
arr[parentIndex] = temp;
}
function build_heap(arr) {
for (let i = arr.length - 2; i >= 0; i--) {
down_adjust(i, arr.length, arr);
}
}
var a = [7, 1, 3, 10, 5, 2, 8, 9, 6]
build_heap(a); // 最小二叉堆的自均衡
while (a.length) {
console.log(a.shift()); // 输出0~9
build_heap(a)
}
console.log(count); // 23
上面的代码是书本里面介绍的方法,简直扯淡,完全就是遍历,下面是二叉堆的上浮
var count = 0;
function up_adjust (arr) { // 下沉操作
let childIndex = arr.length - 1;
let childOffset = childIndex % 2 === 0 ? 2 : 1; // 右孩子
// 取余二等于零 就是一个右孩子
let parentIndex = (childIndex - childOffset) / 2;
let temp = arr[childIndex];
while (childIndex > 0 && temp < arr[parentIndex]) {
count++;
// 子元素存在 并且 子元素小于父元素
// 父元素下沉
arr[childIndex] = arr[parentIndex];
childIndex = parentIndex;
childOffset = childIndex % 2 === 0 ? 2 : 1; // 右孩子
// 取余二等于零 就是一个右孩子
parentIndex = (childIndex - childOffset) / 2;
}
// 子元素上浮
arr[childIndex] = temp;
}
var a = [1, 5, 2, 6, 7, 3, 8, 9, 10, 0]
up_adjust(a);
console.log(a); [0, 1, 2, 6, 5, 3, 8, 9, 10, 7]
console.log(count); // 3
每个父节点都大于他左右孩子的值 最大堆
优先队列,每次把头元素出掉,然后树自均衡一下,然后在出,在自均衡。
代码略
为什么优先队列比循环排序输出更优呢,下面省略if比较的执行次数计算
假设长度为10的无序数值数值,要排序输出,最少要55次执行,冒泡排序执行45(10 * 10 / 2 + 10 / 2 - 10)次,循环输出10次。
优先队列,
出队列1,首次自均衡 9 - 2 = 7
出队列1 ,自均衡 8 - 2 = 6
…
10次输出完毕,7+6+5+4+3+2+1 = 28次 ,构建二叉堆1,1(和树深度一致) …
[1, 1,1,2,2,2,2,3,3,3] 最大 20次 总共 45次
如果100次的话
循环 99 99 / 2 + 99 / 2 = 4950
优先队列 97 97 /2 + 97 / 2 = 4753 + 127 = 4880 比循环更优先,但是按实际情况,可能次数更少一些
// 计算树的层次
for (let i = 100, x = 1; i > 1; i /= 2, x++) {
console.log(i, x);
}
/*
100 1
VM1643:2 50 2
VM1643:2 25 3
VM1643:2 12.5 4
VM1643:2 6.25 5
VM1643:2 3.125 6
VM1643:2 1.5625 7
7层, 除掉根
2一次方
2二次方
...
2的六次方
*/
var count = 0
for (let i = 6; i > 0; i--) {
count += Math.pow(2, i)
}
126 + 1