堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆排序的平均时间复杂度为 Ο(nlogn)。堆是一种特殊的二叉树,近似完全二叉树,同时满足所有的节点都大于等于(最大堆)或小于等于(最小堆)每个它的子节点。
堆结构实现参考。
1. 算法步骤
- 使用数组结构构建最大堆或最小堆;
- 将堆的根节点(最大/小值)和堆的最后一层某个叶子节点交换位置,然后将堆的大小减一;
- 将新的堆结构堆化,即重新构建为最大/小堆;
- 重复步骤二和步骤三,直到堆的大小为一。
2. 图片演示
3. 代码实现
本文使用的typescript实现,有兴趣的同学可以自己转换为JavaScript试试。
/**
* 堆排序,改变原数组
* @param arr 待排序数组
* @param compareFn 比较函数: a > b 升序(构建最大堆),b > a 降序(构建最小堆)
* @returns
*/
function heapSort<T = unknown>(arr: T[], compareFn: (a: T, b: T) => boolean) {
/**
* 通过下移操作堆化:找出自身节点和左右子节点中的最大/小节点,然后交换位置,保证自身大于等于或小于等于子节点
* @param idx 需要堆化的节点位置
* @param size 堆在数组中结束位置即堆的大小
* @param simpleArr 完整数组
*/
const siftDown = (idx: number, size: number, simpleArr: T[]) => {
let tempIdx = idx;
const leftIdx = tempIdx * 2 + 1;
const rightIdx = tempIdx * 2 + 2;
if (leftIdx < size && compareFn(simpleArr[leftIdx], simpleArr[tempIdx])) {
tempIdx = leftIdx;
}
if (rightIdx < size && compareFn(simpleArr[rightIdx], simpleArr[tempIdx])) {
tempIdx = rightIdx;
}
if (tempIdx === idx) {
return;
}
[simpleArr[idx], simpleArr[tempIdx]] = [simpleArr[tempIdx], simpleArr[idx]];
};
const buildHeap = (len: number, arr: T[]) => {
// 一个数组只需要通过下移 (arr.length-1) / 2 次就可以完全堆化
const begin = Math.floor((len - 1) / 2);
for(let i = begin; i >= 0; i--) {
siftDown(i, len, arr);
}
};
let size = arr.length;
while(size > 1) {
buildHeap(size, arr);
// 将堆的最大/小值和堆的最后一个元素交换位置,然后将堆的大小减一
[arr[0], arr[size - 1]] = [arr[size - 1], arr[0]];
size--;
}
return arr;
}
至此我们就实现了一个堆排序算法,有兴趣的童鞋可以自己试试哦~