描述
将整个数组变成一个大根堆,则大根堆最上面的那个数就是最大的数,每次都将最大的数提炼出来,放在数组后面(每向后面放一个当前最大数,就将数组的数量减少一,这样每次放的时候都是在之前放置的数的前面),就达成了排序。
PS:
第一次提炼之前需要将整个数组变成一个大根堆,也就是建树。
每次提炼出来最大的数之后,需要对剩余的元素进行调整,使他们再次变成一个大根堆,依次循环。
js代码
let arr = [23, 321, 51, 2, 1, 42, 1, 41, 12];
heapSort(arr);
console.log(arr);
//维护一个 已经有序堆 的大根堆
function heapify(arr, index, heapSize) {
let left = index * 2 + 1;
while (left < heapSize) {
//找出两个孩子中最大的那个孩子
let largest = left + 1 < heapSize && arr[left] < arr[left + 1] ? left + 1 : left;
//父亲跟最大的孩子进行比较,选择最大的数
largest = arr[largest] > arr[index] ? largest : index;
//如果仍然是父亲最大,直接跳出
if (index == largest) break;
//否则继续进行调整
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
//创建树
function buildTree(arr) {
//找出最后一个非叶子节点(因为对叶子节点进行维护是没有必要的)
let j = parseInt(arr.length / 2 - 1);
for (let i = j; i >= 0; i--) {
heapify(arr, i, arr.length)
}
}
//堆排序
function heapSort(arr) {
//先将整个数组变成一个大根堆
buildTree(arr);
let heapSize = arr.length;
//开始提炼每一次最大的数,放在数组最后
swap(arr, 0, --heapSize);
while (heapSize > 0) {
heapify(arr, 0, heapSize)
swap(arr, 0, --heapSize);
}
}
function swap(arr, i, j) {
let t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}