堆:符合以下两个条件之一的完全二叉树:
根节点的值 ≥ 子节点的值,这样的堆被称之为最大堆,或大顶堆;
根节点的值 ≤ 子节点的值,这样的堆被称之为最小堆,或小顶堆。
堆排序的基本思想:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根结点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,就能得到一个升序序列。
步骤一:构造初始堆.将给定无序序列构造成一个大顶堆
1.假定给定无序序列结构如下:
2.从最后一个非叶子结点开始,从左至右,从下至上进行调整
第一个非叶子结点:
第二个非叶子结点:
3.这时,交换导致子根[4,5,6]结构混乱,进一步调整,在代码中体现为:parent = child
child = 2*parent+1
.调整结束后,就将一个无序序列构造成了一个大顶堆.
步骤二:将堆顶元素与末尾元素交换,使末尾元素最大.然后继续调整堆,再将堆顶元素与末尾元素交换,得到第二大元素.如此反复进行交换、重建、交换.
代码实现
void adjustHeapDown(int arr[], int index, int len){
if(arr == NULL || index >= len){
return;
}
int parent = index;
int child = 2 * parent + 1;
while (child < len){
if(child + 1 < len && arr[child] < arr[child + 1]) {
child++;
}
if(arr[child] > arr[parent]) {
swap(arr[child], arr[parent]);
} else {
break;
}
parent = child;
child = 2 * parent + 1;
}
}
void sortHeap(int arr[], int len){
//1.构建大顶堆
for(int i = (len - 2)/2; i >= 0; i--){
adjustHeapDown(arr, i, len);
}
//2.调整堆结构 + 交换堆顶元素与末尾元素
for(int i = len - 1; i > 0; i--){
swap(arr[0],arr[i]);
adjustHeapDown(arr, 0, i);
}
}