先上代码
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 ! ! 感谢观看!!
== ================================ ==
寄扬州韩绰判官 杜牧 唐
青山隐隐水迢迢,秋尽江南草未凋。
二十四桥明月夜,玉人何处教吹箫。