算法导论—排序算法学习(3)
来源:互联网 发布:win10软件限制策略 编辑:程序博客网 时间:2024/06/05 00:46
三.堆排序
堆排序与归并排序一样,他们的时间复杂度都是o(log n),但是堆排序优于归并排序且与插入排序相同的是,任何时候都只需要申请常数个临时空间来存储数据。因此,堆排序是集合了归并排序与插入排序优点的一种排序方法。
涉及到堆排序,首先要了解堆这种数据结构。堆是一个数组,它可以被看成一个近似的完全二叉树,树上的每一个节点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左向右填充。需要注意的是,当根节点是从1开始计算个数时,我们很容易计算的到它的父节点,左孩子和右孩子的下标。假设父节点下标是i,左孩子下标应该是2i,右孩子下标应该是2i+1。如果根节点是从0开始计算个数时,左孩子下标应该是2i+1,右孩子是2i+2。
堆可以分为两种形式:最大堆和最小堆。最大堆性质是指除了根以外的所有节点 i 都要满足A[parent[i]]>=A[i];而最小堆性质是指除了根以外的所有节点 i 都要满足A[parent[i]]<=A[i];在堆排序中,我们使用最大堆。
下面介绍堆排序需要的过程以及代码:
MaxHeapify是用于维护最大堆性质的重要过程,它的输入为一个数组A和下标 i 。在调用此函数时,我们假定根节点为Left(i)和Right(i)的二叉树都是最大堆,但这时A[i]有可能小于其孩子,这样就违反了最大堆的性质。MaxHeapify通过让A[i]的值在最大堆中逐级下降,从而使得下标 i 为根节点的子树重新遵循最大堆的性质。
void MaxHeapify(int *Array,int num,int i) //num为数组长度,i为待最大堆化的下标 { int left,right,mid,media; left = 2*i+1; //将该下标对应的左孩子下标赋给left right = 2*(i+1); //将该下标对应的右孩子下标赋给right if(left<=(num-1) && Array[i]<Array[left]) //当左右孩子不为空时,找出父节点与左右孩子之间的最大值 mid = left; else mid = i; if(right<=(num-1) && Array[mid]<Array[right]) mid = right; if(i != mid) //若父节点不为最大值,则进行交换 { media = Array[i]; Array[i] = Array[mid]; Array[mid] = media; MaxHeapify(Array,num,mid); //将交换过后的值进行递归操作,继续进行最大堆化 } }
有了最大堆化的操作过程,将任意一个数组变成一个最大堆的操作就成为可行的了,由二叉树的性质可知,子数组A[0,1,2…(num/2)-1]都不是叶节点,即只需要对这些元素遍历最大堆化即可:
void BuildMaxHeap(int *Array,int num){ int i; for(i=(num/2)-1;i>=0;i--) MaxHeapify(Array,num,i);}
下面是堆排序的过程:
void HeapSort(int *Array,int num){ int i,media; BuildMaxHeap(Array,num); //首先将一个无序数组建成一个最大堆 for(i=num-1;i>=1;i--) //此时,数组首元素必为最大元素 { //将数组末尾元素与首元素进行交换 media = Array[i]; //交换后则当前数组最大元素位置正确 Array[i] = Array[0]; Array[0] = media; num -= 1; //排序好一个元素后将最大堆减少一个节点 MaxHeapify(Array,num,0); //因为末尾元素此时在根节点需要重新进行最大堆化 }}
- 算法导论—排序算法学习(3)
- 算法导论—排序算法学习(1)
- 算法导论—排序算法学习(2)
- 学习算法导论——插入排序
- 学习算法导论——选择排序
- 学习算法导论——冒泡排序
- 学习算法导论——堆排序
- 学习算法导论——快速排序
- 归并排序——算法导论学习
- 选择排序—算法导论学习
- 插入排序算法学习——算法导论学习笔记
- 算法导论学习笔记(3)---计数排序
- 算法导论学习日记(3)--合并排序
- 《算法导论》学习笔记(2)——快速排序
- 算法导论学习------归并排序
- 插入排序-算法导论学习
- 算法导论学习1--排序
- 冒泡排序算法分析——《算法导论》学习笔记
- 线段树
- 生产环境下JAVA进程高CPU占用故障排查
- jincheng zhanyong
- 单链表逆序
- 金属圆筒单节充电宝 2600毫安18650电芯小巧便携移动电源
- 算法导论—排序算法学习(3)
- #define UNUSED_PARAM(v) (void)(v) 的作用
- (十三)洞悉linux下的Netfilter&iptables:为防火墙增添功能模块【实战】
- 使用cocos2d-js-3.0RC1中的物理引擎chipmunk模拟的“别碰钉子”源码分享(含碰撞检测)
- java的背景及就业
- Android消息队列模型——Thread,Handler,Looper,Massage Queue
- Android数据存储(一):SharedPreferences存储
- IE兼用性问题
- win8用久了变得很慢, 磁盘占用100%