堆的实现、堆排序、优先队列
2017-09-22 00:12
302 查看
一、小根堆的实现、第一种堆排序
输入一组数据;创建一个小根堆:从最后一个非叶子结点到第1个结点依次进行向下调整;
新增一个值:将新元素插入到末尾,再根据情况判断新元素是否需要上移,直到满足堆的特征为止;
【第一种堆排序】从小到大排序:对于小根堆,每次将顶部元素输出并删除顶部元素(最后一个元素移至顶部,堆的大小减1,继续向下调整),直到堆空。
测试示例
14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
Y
55
#include <stdio.h> int h[101];//用来存放堆的数组 int n;//用来存储堆中元素的个数,也就是堆的大小 //交换函数,用来交换堆中的两个元素的值 void swap(int x,int y){ int t=h[x]; h[x]=h[y]; h[y]=t; } //向下调整函数 void siftdown(int i){//传入一个需要向下调整的结点编号i.这里传入1,即从堆的定点开始向下调整 int t,flag=0;//flag用来标记是否需要继续向下调整 //当i结点有儿子(至少有左儿子)并且有需要继续调整的时候循环就执行 while(i*2<=n&&flag==0){ //首先判断它和左儿子的关系,并且用t记录较小的结点编号 if(h[i]>h[i*2]) t=i*2; else t=i; //如果它有右儿子,再对右儿子进行讨论 if(i*2+1<=n) if(h[i*2+1]<h[t]) t=i*2+1; //如果最小的结点编号不是自己,说明子结点有比编号比父结点小的 if(t!=i){ swap(t,i); //交换它们 i=t;//更新i为刚才与它交换的儿子结点的编号,以便继续向下调整 } else flag=1;//否则说明当前的父结点已经比两个子结点都要小了了,不需要继续调整了 } } void siftup(int i){//传入一个需要向上调整的结点编号i int flag=0;//用来标记是否需要继续向上调整 if(i==1) return;//如果是堆顶就返回 //不是堆顶,并且当前结点比父结点小就继续向上调整 while(i!=1&&flag==0){ //判断是否比父结点小 if(h[i]<h[i/2]) swap(i,i/2);//交换它和它爸爸的位置 else flag=1;//表示已经不需要继续调整了 i=i/2;//更新编号i为它父结点的编号,从而便于下一次继续向上调整 } } //建立堆的函数 void creat(){ int i; //从最后一个非叶子结点到第1个结点依次进行向下调整 for(i=n/2;i>=1;i--) siftdown(i); } //删除最大的数 int deletemax(){ int t=h[1];//用一个临时变量记录堆顶点的值 h[1]=h ;//将堆的最后一个点赋值到堆顶 n--;//堆的元素减少1; siftdown(1);//向下调整 return t;//返回之前记录的堆的顶点的最小值 } int main() { int i,num; //读入要排序的数字的个数 scanf("%d",&num); n=num; for(i=1;i<=num;i++) scanf("%d",&h[i]); //建堆 creat(); //增加一个新元素 printf("是否增加一个新元素(Y/N): "); char ch; getchar(); scanf("%c",&ch); if(ch=='Y'){ num++;n++; scanf("%d",&h ); siftup(n); } //删除顶部元素,连续删除n次,其实就是从小到大把数输出来 printf("排序后:\n"); for(i=1;i<=num;i++) printf("%d ",deletemax()); return 0; }
二、最大堆、第二种堆排序
输入一组数据;创建一个大根堆:从最后一个非叶子结点到第1个结点依次进行向下调整;
【第二种排序】从小到大排序:建立大根堆,因为希望从小到大排序,所以最大的放在最后。每次将h[1]和h
交换,堆大小减1(n–),然后h[1]向下调整,直至堆的大小为1。
测试示例
14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
#include <stdio.h> int h[101];//用来存放堆的数组 int n;//用来存储堆中元素的个数,也就是堆的大小 //交换函数,用来交换堆中的两个元素的值 void swap(int x,int y){ int t=h[x]; h[x]=h[y]; h[y]=t; } //向下调整函数 void siftdown(int i){//传入一个需要向下调整的结点编号i.这里传入1,即从堆的定点开始向下调整 int t,flag=0;//flag用来标记是否需要继续向下调整 //当i结点有儿子(至少有左儿子)并且有需要继续调整的时候循环就执行 while(i*2<=n&&flag==0){ //首先判断它和左儿子的关系,并且用t记录较大的结点编号 if(h[i]<h[i*2]) t=i*2; else t=i; //如果它有右儿子,再对右儿子进行讨论 if(i*2+1<=n) if(h[i*2+1]>h[t]) t=i*2+1; //如果最小的结点编号不是自己,说明子结点有比编号比父结点大的 if(t!=i){ swap(t,i); //交换它们 i=t;//更新i为刚才与它交换的儿子结点的编号,以便继续向下调整 } else flag=1;//否则说明当前的父结点已经比两个子结点都要大了,不需要继续调整了 } } //建立堆的函数 void creat(){ int i; //从最后一个非叶子结点到第1个结点依次进行向下调整 for(i=n/2;i>=1;i--) siftdown(i); } //堆排序 void heapsort(){ while(n>1){ swap(1,n); n--; siftdown(1); } } int main() { int i,num; //读入要排序的数字的个数 scanf("%d",&num); n=num; for(i=1;i<=num;i++) scanf("%d",&h[i]); //建堆 creat(); //堆排序 heapsort(); //输出 printf("排序后:\n"); for(i=1;i<=num;i++) printf("%d ",h[i]); return 0; }
三、优先队列
像这样支持插入元素和寻找最大(小)值元素的数据结构称为优先队列。而堆就是优先队列的实现。
相关文章推荐
- 优先队列(二叉堆实现) + 堆排序
- 算法基础:排序(四)——二叉堆、优先队列、堆排序——Python实现
- 最小堆得实现;优先队列的堆实现;堆排序的时间复杂度nlgn;
- 算法基础:排序(四)——二叉堆、优先队列、堆排序——Python实现
- 堆排序实现优先队列(Priority queue)
- 用java实现一个基于堆排序的优先队列
- 利用优先队列实现堆排序(自顶向下自底向上堆化全然二叉树的运用)
- 堆排序实现优先队列
- 算法设计之,堆,堆排序,基于最大堆的最大优先队列的实现(C++实现)
- 基于二叉堆实现的优先队列和堆排序
- 二叉堆,堆排序,STL优先队列的底层实现,剑指offer数据流中的中位数
- 利用优先队列实现堆排序(自顶向下自底向上堆化完全二叉树的运用)
- 优先队列 之 堆排序实现(堆排序思想)
- java编程实现优先队列的二叉堆代码分享
- 优先队列和堆排序
- 利用堆实现堆排序&优先队列
- 用STL实现优先队列
- 【数据结构】堆,堆实现优先级队列,堆排序
- Python实现最大优先队列
- 优先队列(堆) - C语言实现(摘自数据结构与算法分析 C语言描述)