堆排序 javascript版
算法思路参考《算法导论》
代码
/**
* 时间复杂度 平均:O(nlog2n)。
* 空间复杂度:O(1)。
* 稳定性:不稳定
*/
var array = [];
var int = 0;
for (var i = 0; i < 9; i++) {
int = Math.ceil(Math.random() * 10);
array.push(int);
}
console.log(array);
//不稳定排序
function HeapSort(arr) {
var len = arr.length;
BuildMaxHeap(arr,len);
for (var i = len-1 ; i > 0; i--) {
let box = arr[0];
arr[0] = arr[i];
arr[i] = box;
MaxHeap(arr,0,i);
}
return arr
}
function MaxHeap(arr,i,length) {
var largest = null;
var node = arr[i]; //保存当前节点
var left = i * 2 + 1 ; //定位节点左
var right = i * 2 + 2; //定位节点右
//判断当前有这个节点 (这里会存在当前这个的子节点不存在的情况)处理一下边界情况
if (left < length && node < arr[left]) {
largest = left
}else{
largest = i;
}
if (right < length && arr[largest] < arr[right]) {
largest = right
}
//如果不是i是最大节点 以node作为辅助节点 交换位置
if (largest != i) {
arr[i] = arr[largest];
arr[largest] = node;
MaxHeap(arr,largest,length);
}
}
//建立一个最大堆
function BuildMaxHeap(arr,len){
if(len%2!=0){
len = len +1 ;
}
for(let i = len/2;i>=0;i--){
MaxHeap(arr,i,len)
}
}
console.log(HeapSort(array));
算法思路
::: tip 说明 因为上面的代码是升序的所以就以升序来说明 :::
- 建立一个初始堆,升序采用 大顶堆
BuildMaxHeap
这个函数用来建立初始的大顶堆
if(len%2!=0){
len = len +1 ;
}
剩下的一个也算一个单独的小堆😁
for(let i = len/2;i>=0;i--){
MaxHeap(arr,i,len)
}
实现大顶堆,先来看 MaxHeap
这个函数
largest
用于存放最大值
node
用来保存当前节点
从下图中可以看到 当前节点的左节点为2i+1的位置。右节点为2i+2的位置。

//判断当前有这个节点 (这里会存在当前这个的子节点不存在的情况)处理一下边界情况
if (left < length && node < arr[left]) {
largest = left
}else{
largest = i;
}
if (right < length && arr[largest] < arr[right]) {
largest = right
}
//如果不是i是最大节点 以node作为辅助节点 交换位置
if (largest != i) {
arr[i] = arr[largest];
arr[largest] = node;
MaxHeap(arr,largest,length);
}
这一段代码做的事情其实就是把最大的那个数字放到 这个小堆的堆顶。因为元素的位置发生了交换,那么他的子节点可能也是不符合最大堆的性质的,所以这里要递归调用。
在去看BuildMaxHeap
这个函数 就是从完整堆的最底层(len/2) 一层一层慢慢往上排 最终完整实现最大堆。
最后的排序实现函数HeapSort
for (var i = len-1 ; i > 0; i--) {
let box = arr[0];
arr[0] = arr[i];
arr[i] = box;
MaxHeap(arr,0,i);
}
box
是交换容器。这段代码做的事情,就是把堆顶最大的值和末尾的数字交换,那么数组最后的数字就是最大值。 MaxHeap(arr,0,i) 这里传值i是每交换一次 数组末尾的值就是正确的值。 在下一次调整的时候就把这个位置排除了。