排序算法之堆排序
2015-08-19 21:45
295 查看
1、 堆排序的思想
输入一个数组,利用一组二叉树的操作使其变成有序的数组,就是堆排序堆排序利用的是二叉树的思想,操作对象是数组,所以数组需要在逻辑上映射到二叉树上,由于数组的下标是连续的,而二叉树中只有完全二叉树和满二叉树是连续的,所以将数组元素逐个映射到完全二叉树上,然后配备一系列的操作即可。例如数组data[]={9,6,5,4,3,2,1,7},映射到完全二叉树上如下图所示。
2、堆排序的过程
还是用上面的data数组作为输入数组,映射到完全二叉树如上图所示,怎么利用二叉树的性质,才能使得数组有序呢?首先需要取得二叉树中的最大值(或者最小值),显然需要建立最大堆,取得二叉树的根节点即最大值,放置在数组中最后一个位置上,再将二叉树中的最后一个节点放置在根节点上,调整堆使其变成最大堆,取最大值放在数组中倒数第二个位置上.......这样的调整需要n-1次,数组有序。总结上述过程,堆排序需要三个步骤:
A、根据输入数组,建立最大堆
B、保持最大堆的性质
C、循环n-1次,找到(n-1)堆中每个堆的最大值并放置在数组中,数组有序
首先,这三个过程中,我觉得最重要的是保持最大的堆的性质,其实就是在二叉树中不断使元素下行,直至满足最大堆的要求。需要知道,数组中下标为i的元素,它的左孩子下标是2i+1,右孩子的下标是2i+2,保持最大堆函数的伪代码如下所示(伪代码--算法导论上第75页)。
MAX_HEAPFY(A,i) l=LEFT(i) //l=2*i+1 r=LEFT(i) //r=2*i+2 if(l<=heap_size(A)&&A[i]<A[l]) largest=l; //largest记录最大值下标 else largest=i; if(r<=heap_size(A)&&A[largest]<A[r]) largest=r; if(i!=largest) //如果largest不是i,则说明现在不是最大堆,需要调整 exchange(A[i],A[largest]) //使下标i上的元素具有最大值,然后继续向下调整 MAX_HEAP(A,largest)
其次,在完成max_heapfy后,接下来的工作就是根据输入数组建立最大堆,由max_heapfy知道,函数的参数i代表的是根节点的下标,在一个长度为len的数组中,下标最大的根节点的下标是(i/2),我们可以从下到上依次调整形成最大堆,这个过程就是建立最大堆的过程,与MAX_HEAPFY调整函数不同,这个过程是一个元素上行的过程。建堆的伪代码如下所示。
BUILD_MAX_HEAP(A) heap_size(A)=length(A) for(int i=length(A)/2;i>=0;i--) MAX_HEAPFY(A,i)
最后,完成以上两步后,取最大堆的堆顶元素,放置在数组中对应的位置上,不断循环,这个过程需要进行length(A)-1次,数组便可有序。这个过程的伪代码如下所示。
HEAPSORT(A) BUILD_MAX_HEAP(A) for(int i=length(A)-1;i>=1;i--) exchange(A[0],A[i]); heap_size(A)=heap_size(A)-1 MAX_HEAPFY(A,0);
3、堆排序的时间复杂度分析:
由上述说明,堆排序的输入数组和一个完全二叉树对应,假设数组大小时N,则二叉树的高度是lgN,所以保持最大堆性质的调整操作所需要的时间复杂度是O(lgN),而建立一个最大堆的时间复杂度是O(n)(这个结论的推导在算法导论的第78页),最后的排序时间复杂度为(n-1)*lgN所以,这个堆排序的时间复杂度是T(N)=O(N)+(n-1)*lgN,T(N)=O(NlgN),需要说明的一点是堆排序对于输入的数据的随机性没有特别的要求,也就是说,在最好、最坏和平均情况下,堆排序的时间复杂度都是O(nlgn)
4、堆排序的稳定性说明
堆排序不是一种稳定的排序方法。附上堆排序的代码(codeblocks已通过):
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <iostream> #include <algorithm> using namespace std; void max_heapfy(int data[],int heap_size,int i){ int left=2*i+1; int right=2*i+2; int largest; if(left<heap_size&&data[left]>data[i]) largest=left; else largest=i; if(right<heap_size&&data[right]>data[largest]) largest=right; if(largest!=i){ swap(data[i],data[largest]); max_heapfy(data,heap_size,largest); } } void build_heap(int data[],int length){ for(int i=length/2-1;i>=0;i--) max_heapfy(data,length,i); } void heap_sort(int data[],int length){ if(data==NULL||length<=0) return ; build_heap(data,length); int heap_size=length; for(int i=length-1;i!=0;i--){ swap(data[i],data[0]); heap_size-=1; max_heapfy(data,heap_size,0); } } int main(){ int data[]={6,5,4,9,7,8,2,1,3,5}; int length=sizeof(data)/sizeof(int); heap_sort(data,length); for(int i=0;i<length;i++) cout << data[i] << " "; return 0; }
相关文章推荐
- PostgreSQL Replication之第四章 设置异步复制(8)
- sublimeText注册
- Linux环境进程间通信(五): 共享内存(上)
- HDOJ 2084 数塔 【dp】
- HDOJ 2084 数塔 【dp】
- 关于c++派生类构造函数的思考
- 2016 360笔试题------找第一个只出现一次的字符
- Servlet 工程 web.xml 中的 servlet 和 servlet-mapping 标签
- R语言入门基础
- ZOJ 1109 Language of FatMouse
- POJ1850——Code
- ubuntu12.04更新时签名错误(BADSIG 40976EAF437D05B5)
- poj1734(floyd算法)
- SVN使用小结
- Java编程思想读书笔记:第2章 一切都是对象
- [150130] 1/7の魔法使い【日文硬盘版】带BT种子镜像版(带全CG存档+转码打开补丁+存档文件夹补丁)
- json数据转化成模型对象
- [洛谷1314]无序字母对
- SVN使用小结
- phaser游戏开发之基础知识1