[数据结构]堆排序
2017-04-30 16:41
260 查看
算法思想
堆排序是一种树形选择排序方法,它的特点是:在排序过程中,将L[1…n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或者最小)的元素。堆的定义如下:n个关键字序列L[1…n]称为堆,当且仅当该序列满足:
①L(i)≤L(2i)且L(i)≤L(2i)或 ②L(i)≥L(2i)且L(i)≥L(2i+1)
满足第一种情况的堆称为小根堆,满足第二种情况的称为大根堆。显然,在大根堆中,最大元素存放在根结点中,且对其中任意一个非根结点,它的值小于或等于其双亲结点值。小根堆的定义刚好相反,根结点是最小元素。
堆排序的关键是构造初始堆,对初始序列建堆,就是一个反复筛选的过程。n个结点的完全二叉树,最后一个结点是第[n/2]个结点的孩子。对第[n/2]哥结点为根的子树筛选(对于大根堆:若根结点的关键字小玉左右子女中关键字较大者,则交换),使该子树成为堆。之后向前依次对各结点([n/2]-1~1)为根的子树进行筛选,看该结点值是否大于其左右子结点的值,若不是,将左右子结点中较大值与其交换,交换后可能会破坏下一级的堆,于是继续采用上述方法构造下一级的堆,直到以该结点为根的子树构成堆位置。反复利用上述调整堆的方法建堆,直到根结点。
算法代码
void BuildMaxHeap(Elemtype A[],int len){ for(int i=len/2;i>0;i--)//从i=[n/2]~1,反复调整堆 AdjustDown(A,i,len); } void AdjustDown(Elemtype A[],int k,int len){ //函数AdjustDown将元素k向下进行调整 A[0]=A[k];//A[0]暂存元素 for(i=2*k;i<=len;i*=2){//沿key较大的子结点向下筛选 if(i<len&&A[i]<A[i+1]) i++;//取key较大的子结点的下标 if(A[0]>=A[i]) reak;//筛选结束 else{ A[k]=A[i];//将A[i]调整到双亲结点上 k=i;//修改k的值,以便继续向下筛选 } } A[k]=A[0];//被筛选结点的值放入最终位置 }
向下调整的时间和树高有关,为O(h),建堆过程中每次向下调整时,大部分结点的高度都较小。因此,可以证明在元素个数为n的序列上建堆,其时间复杂度为O(n),这说明可以在线性时间内,将一个无序数组建成一个大根堆。
应用堆这种数据结构进行排序的思路很简单,首先将存放在L[1…n]中的n个元素建成初始堆,由于堆本身的特点(以大根堆为例),堆顶元素就是最大值。输出堆顶元素后,通常将堆底元素送入堆顶,此时根结点已不满足大顶堆的性质,堆被破坏,将堆顶元素向下调整使其继续保持大顶堆的性质,再输出堆顶元素。如此重复,直到堆中仅剩下一个元素为止。
下面是堆排序算法:
void HeapSort(Elemtype A[],int len){ BuildMaxHeap(A,len);//初始建堆 for(i=len;i>1;i--){//n-1趟的交换和建堆过程 swap(A[i],A[1]);//输出堆顶元素(和堆底元素交换) AdjustDown(A,1,i-1);//整理,把剩余的i-1个元素整理成堆 } }
同时,堆也支持删除和插入操作。由于堆顶元素或为最大值或最小值,删除堆顶元素时,先将堆的最后一个元素与堆顶元素交换。由于此时堆的性质被破坏,将堆顶元素向下调整操作。对堆进行插入操作时,先将新结点放在堆的末端,再对这个新结点执行向上调整操作。
下面是向上调整堆的算法:
void AdjustUp(Elemtype A[],int k){ //参数k为向上调整的结点,也为堆的元素个数 A[0]=A[k]; int i=k/2;//若结点值大于双亲结点,则将双亲结点向下调,并继续向上比较 while(i>0&&A[i]<A[0]){ A[k]=A[i];//双亲结点下调 k=i; i=k/2;//继续向上比较 } A[k]=A[0];//复制到最终位置 }
算法复杂度
空间复杂度:仅使用了常数个辅助单元,所以空间复杂度为O(1)。时间复杂度:建堆时间为O(n),之后有n-1次向下调整的操作,每次调整的时间复杂度为O(log₂n)。所以时间复杂度为O(nlog₂n)。
稳定性:在进行筛选时,有可能把后面相同关键字的元素调整到前面,所以堆排序算法是一种不稳定的排序方法。例如,表L={1,2,2},构造初始堆时,可能将2交换到堆顶,此时L={2,1,2},最终排序序列为L={1,2,2},显然,2和2的相对次序已经发生了变化。
相关文章推荐
- 数据结构_堆排序
- 数据结构 - 堆排序(heap sort) 详解 及 代码(C++)
- ACM入门(2)——数据结构——堆排序
- 数据结构_内部排序_希尔排序_快速排序_堆排序_归并排序_地址排序
- 数据结构 排序(堆排序)
- 数据结构学习笔记5-寻找最小的k个数(选择排序和堆排序)
- 数据结构&算法实践—【排序|选择排序】堆排序
- 数据结构-排序-堆排序
- 算法和数据结构---排序---堆排序
- 【数据结构】常用比较排序算法(包括:选择排序,堆排序,冒泡排序,选择排序,快速排序,归并排序)
- java 数据结构之堆排序(HeapSort)详解及实例
- 数据结构 二叉堆 & 堆排序
- 【算法与数据结构】冒泡、插入、归并、堆排序、快速排序的Java实现代码
- 数据结构 - 堆排序
- 数据结构与算法之堆与堆排序
- 【数据结构】Java实现各类经典排序算法——桶排序、堆排序
- c++实现数据结构中的各种排序方法:直接插入、选择,归并、冒泡、快速、堆排序、shell排序
- 数据结构-排序-堆排序
- 数据结构中堆的建立,建小堆,以及堆排序
- 数据结构---------堆排序