先上代码
void swap(int a[], int i, int j) { int t = a[i]; a[i] = a[j]; a[j] = t; } void heapify(int tree[], int n, int i) // 从第 i 个 开始做 heapify { if (i >= n) return; int c1 = 2 * i + 1; int c2 = 2 * i + 2; int max = i; if (c1 < n&&tree[c1] > tree[max]) max = c1; if (c2 < n&&tree[c2] > tree[max]) max = c2; if (max != i) { swap(tree, max, i); heapify(tree, n, max); } } void build_heap(int tree[], int n) { int last_node = n - 1; int parent = (last_node - 1) / 2; for (int i = parent; i >= 0; i--) heapify(tree, n, i); } void heap_sort(int tree[], int n) { build_heap(tree, n); for (int i = n - 1; i >= 0; i--) { swap(tree, i, 0); heapify(tree, i, 0); } } int main(void) { #define N 1086 int a[N] = { 0 }; int n; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } heap_sort(a, n); for (int i = 0; i < n; i++) { printf("%d ", a[i]); }puts(""); system("pause"); return 0; }
一,先看 heapify 函数
heapify 是构造完全二叉树需要用到的特定的操作,所以单独列出一个函数:
二叉树数据间是没有任何关系的,而这个函数是把二叉树的父与子中父找出来,并移到父的位置,
并用递归调用 维护交换后,被破环的子节点与其子结点的关系,直到越界
二,build_heap
这个是用来构造 完全二叉树
这里要区分一点是:
① heapify 是对一个父结点与两结点进行排序。递归调用之后,它所走的路程是 从结点开始向下找最大值,
所以必须存在比父结点大的子结点,它才能继续往下走
所以 heapify第一个结点是不能构造 heap 的。
② 所以要用到 build_heap 函数:
先找到最后一个父结点,在从父结点开始调用 heapify ,从下面往上构造。
三,heap_sort
先明白一下 完全二叉树并不是完全排好序,但第一个结点一定是所有元素中最大的。
所以,就可以利用这点去排序
1,既然已经是最大的,那么就把这个数提走,剩下的在 heapify
2, 但是这样两个问题,要把最大值放哪?拿走之后,原位置上的元素怎么处理掉?
3,紧接着,我们就知道必须用一个较小值取替换父结点,不然无法 heapify 了,也就无法找到剩下的最大值
那么我们就可以把最后一个结点(它不一定是最小的,但它足够小了)与父节点交换值,
这样就形成了一个效果,最大的在最后面,已经排好了一个
4,然后就把剩下的做一次 heapify ,为什么不是 build_heap,因为它只破坏了父节点,其他完全没动,这就是 heapify 的功能,
这样 heapify 之后就找到剩下的最大值了,
注意每次 heapify 的时候,它的作用范围必须减一,这样才不会波及排好序的元素,
over ! ! 感谢观看!!
== ================================ ==
寄扬州韩绰判官 杜牧 唐
青山隐隐水迢迢,秋尽江南草未凋。
二十四桥明月夜,玉人何处教吹箫。