第一步:构建大顶堆
第二步:将堆顶元素取出(破坏了堆序性),堆尾元素放到堆顶,对新的堆顶元素进行下滤(恢复堆序性),重复此操作。
每次取出的堆顶元素,就是该无序序列的最大值,依次放进堆数组中对应堆尾的下标位置。
这也就是代码中体现的,直接在堆数组中将堆顶元素与堆尾元素交换,再对剔除堆尾的堆进行下滤的过程。
排序思路:
首先,这里采用大顶堆是为了最后升序,显然如果采用小顶堆,最终就是降序;因为排序一般默认都是升序,所以我就选择大顶堆啦。
- 将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点
- 将其与末尾元素进行交换,此时末尾元素就为最大值 ;
- 将剩余n-1个元素重新构造成一个堆(注:只有堆顶元素不满足堆序性,所以只需对堆顶元素进行下滤操作),这样操作之后堆顶元素就又是这n-1个元素的最大值。如此反复执行,便能得到一个有序序列了。
/*交换子节点和根节点元素*/
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
/*1:堆化-->构建大顶堆*/
void maxHeapify(int* arr, int N){
/*对下标为1~N-1的元素分别进行上滤操作(省去新建临时堆空间,挨个插入元素的操作)*/
for(int i = 1, j; i < N; i++){
/*上滤*/
j = i;
while(j){
/*左子节点与根节点比较*/
if(j%2 == 1 && arr[j] > arr[(j-1)/2]){
swap(&arr[j], &arr[(j-1)/2]);
j = (j-1)/2;
continue;
}
/*右子节点与根节点比较*/
if(j%2 == 0 && arr[j] > arr[(j-2)/2]){
swap(&arr[j], &arr[(j-2)/2]);
j = (j-2)/2;
continue;
}
/*无元素交换则结束上滤操作*/
break;
}
}
}
/*2:对堆顶元素进行下滤*/
void heapAdjust(int* arr, int index, int N){
int maxIndex = index;
int max = arr[index];
if(2*index + 1 < N && arr[index] < arr[2*index + 1]){
if(max < arr[2*index + 1]){
maxIndex = 2*index + 1;
max = arr[2*index + 1];
}
}
if(2*index + 2 < N && arr[index] < arr[2*index + 2]){
if(max < arr[2*index + 2]){
maxIndex = 2*index + 2;
max = arr[2*index + 2];
}
}
if(maxIndex == index)
return;
swap(arr + index, arr + maxIndex);
heapAdjust(arr, maxIndex, N);
}
/*堆排序*/
void heapSort(int* arr, int N) {
/*构建大顶堆*/
maxHeapify(arr, N);
while(N){
/*堆顶元素与堆尾元素交换*/
swap(arr, arr+ N - 1);
/*除去堆尾,对堆顶元素进行下滤,重新调整为大顶堆*/
heapAdjust(arr, 0, --N);
}
}