问: 什么是堆???
答:把堆存储看成一种树形结构,则根节点小于左右结点的叫做小根堆,根节点大于左右结点的叫大根堆
我们发现如果把所排序的序列换成大根堆序列,则很容易选取到关键字最小的序列,这样不就很方便构建一个递增的序列吗,那么如何建立大根堆呢???
大致思路:把所有非终端结点都检查一遍,是否满足大根堆得要求,如果不满足,则进行调整————检查当前结点是否满足根>=左、右,若不满足,将当前结点与更大的一个孩子互换。
若元素互换破坏了下一级的堆,则采用相同的方法继续往下调整(小元素不断“下坠”)
在顺序存储的完全二叉树中,非终端结点编号i <= ⌊n/2⌋;
现在我们来写代码:
#include<stdio.h>
//这里没有用哨兵,不太习惯用哨兵
void swap(int b[],int i,int j) {
int temp = b[i];
b[i] = b[j];
b[j] = temp;
}
/*对某个结点进行堆排序,这里的i就是代表对哪个结点堆排序*/
void heapify(int b[],int n,int i) {
//看它的左右孩子元素与根节点元素的大小关系
int c1 = 2 * i + 1;
int c2 = 2 * i + 2;
//初始max与根节点元素等同
int max = i;
if (c1<n&&b[c1] > b[max])
max = c1;
if (c2<n&&b[c2] > b[max])
max = c2;
if (max != i) {
swap(b, max, i);
/*递归:这里之所以需要进行递归,是因为
我们再进行这层交换把左右孩子换上去了,
这就回导致左右孩子的堆排序结构破坏,所以必须
对该节点的底层也进行等同操作*/
heapify(b, n, max) ;
}
}
/*从叶子结点进行heapify操作*/
void build_heap(int a,int n) {
int last_node = n - 1;
int i;
int parent = (last_node - 1) / 2;
for (i = parent; i >= 0; i--) {
heapify(a, n, i);
}
}
void heap_sort(int a,int n) {
build_heap(a, n);
int i;
for (i = n - 1; i >= 0; i--) {
swap(a, i, 0);
heapify(a, i, 0);
}
}
int main() {
/*准备一个需要排序的数组{1,3,2,9,7,6,5,2},
这里设置两个两个相同的元素是为了测试算法的
稳定性*/
int a[8] = {1, 3, 2, 9, 7, 6, 5, 2 };
int i;
printf("排序前:");
for (i = 0; i < 8; i++) {
printf("%d\t", a[i]);
}
heap_sort(a, 8);
printf("\n排序后:");
for (i = 0; i < 8; i++) {
printf("%d\t", a[i]);
}
}
这里的代码是看哔站一个up主的视频进行编译的,链接:(我觉得讲的非常清晰,相对于直接告诉我们从非叶子进行递归构建堆序列来说更加清晰明了)