「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」
前言
堆排序是利用树结构所设计的一种排序算法,在排序过程中把n[0...n-1]看成一颗完全二叉树,利用双亲节点和孩子节点之间的关系,构造出大根堆或者小根堆。大根堆也就是每个双亲节点都比孩子节点大,所以根是最大的数字。小根堆意思一样,只不过每个双亲节点都比孩子节点小。我们这里只利用大根堆来排序。堆排序其实就是一个持续构建大根堆的过程,每一趟排序把构建完的大根堆,取出最大值也就是根,放在最末尾的有序区内,然后重复把无序区构建成大根堆,再把根放入有序区内,直到排序完成。
堆排序的时间复杂度为O(nlog2n),空间复杂度为O(1)
过程
堆排序是利用树结构所设计的一种排序算法,在排序过程中把n[0...n-1]看成一颗完全二叉树,利用双亲节点和孩子节点之间的关系,构造出大根堆或者小根堆。大根堆也就是每个双亲节点都比孩子节点大,所以根是最大的数字。小根堆意思一样,只不过每个双亲节点都比孩子节点小。我们这里只利用大根堆来排序。堆排序其实就是一个持续构建大根堆的过程,每一趟排序把构建完的大根堆,取出最大值也就是根,放在最末尾的有序区内,然后重复把无序区构建成大根堆,再把根放入有序区内,直到排序完成。
构建大根堆的代码:
// 比较current节点和他的孩子节点大小,并调整为大的值在前
function HeapAdjust(arr, current, size) {
var temp = arr[current-1];
// 完全二叉树由一个特点,左孩子的位置是双亲节点位置的两倍,则右孩子是两倍加1,所以这里的2*current代表 current 节点的左孩子
for(var j = 2*current; j <= size; j*=2) {
if(j<size && arr[j] < arr[j+1]) ++j;
if(temp > arr[j]) break;
arr[current-1]=arr[j];
current = j;
}
arr[current-1] = temp;
return arr;
}
// 建大根堆
function CreatHeap(arr) {
const len = arr.length;
for(var i = len; i >0; i--) {
HeapAdjust(arr, i, len);
}
}
我们现在知道了大根堆的创建,就可以很容易的写出堆排序算法
function HeapSort(arr) {
// 建初始堆
CreatHeap(arr)
var temp;
console.log('初始堆', arr)
for(let i = arr.length;i>1;i--) {
temp = arr[0];
arr[0] = arr[i-1];
arr[i-1] = temp;
console.log(`第${arr.length-i+1}趟:`, arr)
HeapAdjust(arr, 1, i-1);
}
return arr;
}
时间复杂度:堆排序运行时间主要消耗在建初始堆和调整堆时反复“筛选”上。它的时间复杂度是O(nlog2n)。
空间复杂度:仅需要一个temp临时变量,O(1);堆排序不稳定,数组记录比较高时使用堆排序会更有效率。