算法导论例程——堆排序(大根堆为例)
2016-02-04 23:12
281 查看
堆排序是具有原址性的排序,复杂度为o(nlgn)。
首先要建立一个“堆”的概念,堆 可以理解为二叉树的一种,是节点间有序关系的完全二叉树,即除了最后一层外节点没有缺失,所以可以用数组来表示。对于下标为i的节点,它的子树的左节点的下标为2*i,右节点为2*i+1,父树的节点下标为i/2(向下取整)。而在程序设计中,使用位运算来代替直接*2可以提高运行速度。而某些编译器中会把一些特定的乘法运算改写为位运算。
只把数组建立成堆是没有意义的,我们利用堆的性质,定义了两种特殊的堆,大根堆和小根堆。
大根堆,即任意一个节点都不小于它的两个子节点,这样递归的定义得到的结果之一,就是大根堆的根节点是所有节点中最大的。
小根堆的定义可以类比大根堆。
这里的堆排序以大根堆为例。
首先我们要建立一种方法,就是“大根堆化”(max_heapify)。对于给定的下标,我们计算出它的子树的左节点和右节点的下标,当下标不超过数组的有效长度length时,我们认为这个堆的扩展是有意义的,之后呢我们进行比较,首先比较左节点和给定节点的大小,并通过一个临时变量largest来记录较大节点的下标,之后再比较a[largest]和右节点的大小,同样的,用largest记录较大的下标。这样我们就得到了这三个节点中最大的那个,而当largest不等于给定的节点的下标时,我们交换这两个节点,以保证他们可以满足大根堆的性质。而接下来,被替换的新的子节点又面临同样的问题,即它的子树是否能构成大根堆,这样递归下去,知道无法产生有意义的子树,或是全部子树都满足大根堆的定义。
接下来看如何进行排序,根据上面的性质,我们知道,大根堆的根节点一定是所有节点中最大的,那么我们可以用数组的最末一位和根节点交换,然后缩小数组规模使最后一位不参与接下来的调整,之后再从a[0]建立一次大根堆,不断重复,直到数组被建堆的规模为2,就将原数组按升序重新排序了。
首先要建立一个“堆”的概念,堆 可以理解为二叉树的一种,是节点间有序关系的完全二叉树,即除了最后一层外节点没有缺失,所以可以用数组来表示。对于下标为i的节点,它的子树的左节点的下标为2*i,右节点为2*i+1,父树的节点下标为i/2(向下取整)。而在程序设计中,使用位运算来代替直接*2可以提高运行速度。而某些编译器中会把一些特定的乘法运算改写为位运算。
只把数组建立成堆是没有意义的,我们利用堆的性质,定义了两种特殊的堆,大根堆和小根堆。
大根堆,即任意一个节点都不小于它的两个子节点,这样递归的定义得到的结果之一,就是大根堆的根节点是所有节点中最大的。
小根堆的定义可以类比大根堆。
这里的堆排序以大根堆为例。
首先我们要建立一种方法,就是“大根堆化”(max_heapify)。对于给定的下标,我们计算出它的子树的左节点和右节点的下标,当下标不超过数组的有效长度length时,我们认为这个堆的扩展是有意义的,之后呢我们进行比较,首先比较左节点和给定节点的大小,并通过一个临时变量largest来记录较大节点的下标,之后再比较a[largest]和右节点的大小,同样的,用largest记录较大的下标。这样我们就得到了这三个节点中最大的那个,而当largest不等于给定的节点的下标时,我们交换这两个节点,以保证他们可以满足大根堆的性质。而接下来,被替换的新的子节点又面临同样的问题,即它的子树是否能构成大根堆,这样递归下去,知道无法产生有意义的子树,或是全部子树都满足大根堆的定义。
接下来看如何进行排序,根据上面的性质,我们知道,大根堆的根节点一定是所有节点中最大的,那么我们可以用数组的最末一位和根节点交换,然后缩小数组规模使最后一位不参与接下来的调整,之后再从a[0]建立一次大根堆,不断重复,直到数组被建堆的规模为2,就将原数组按升序重新排序了。
#include <stdio.h> inline int LEFT(int i) { return 2 * i; //左子树的根节点的下标 } inline int RIGHT(int i) { return 2 * i + 1; //右子树的根节点的下标 } void heap_sort(int a[], int length); //堆排序函数 void build_max_heap(int a[], int length); //创建大根堆函数 void max_heapify(int a[], int start, int length); //大根堆化函数 int main() { int a[1000] = { 0 }, n = 0, length = 0, i = 0; printf("请输入要排序的数组规模:"); scanf("%d", &n); length = n; while (n--) scanf("%d", &a[i++]); heap_sort(a, length - 1); i = 0; while (length--) printf("%d,", a[i++]); return 0; } void heap_sort(int a[], int length) { int i = 0; build_max_heap(a, length); for (i = length; i > 0; i--) { a[i] += a[0]; a[0] = a[i] - a[0]; a[i] -= a[0]; max_heapify(a, 0, i - 1); } } void build_max_heap(int a[], int length) { for (int i = length / 2; i >= 0; i--) max_heapify(a, i, length); } void max_heapify(int a[], int start, int length) { int l = LEFT(start), r = RIGHT(start), largest; if (l <= length && a[l] > a[start]) largest = l; else largest = start; if (r <= length && a[r] > a[largest]) largest = r; if (largest != start) { a[largest] += a[start]; a[start] = a[largest] - a[start]; a[largest] -= a[start]; max_heapify(a, largest, length); } }
相关文章推荐
- Help is needed for Dexter
- Vim学习总结
- hihoCoder - 1081 - 最短路径·一:Dijkstra算法
- 自定义等高的cell(xib)
- C++ MFC实现基于RFID读写器的上位机软件
- 列表 块 div和table布局
- 用storyboard和Xib自定义cell常见错误
- 8.MVC框架开发(URL路由配置和URL路由传参空值处理)
- 体育会qwer
- saltstack python api 调用
- Linux网络设置
- 《重构 改善既有代码的设计》学习笔记 1
- Java生成唯一的ID
- 2016/02/04
- qwer
- vs2012与win7不兼容问题
- HDU2841 Visible Trees(容斥原理)
- Java中的堆和栈的区别
- 代理模式
- neuq oj 1009C++统计字符 C++