自建堆排序:
Posted xuan01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自建堆排序:相关的知识,希望对你有一定的参考价值。
建堆(heapification):
蛮力算法
空堆反复调用insert()接口,消耗时间过多,第k轮迭代需O(logK)时间,正比于其深度:总共需要O(log n!) = O(n log n);同理于自顶向下、自左向右的上滤操作;
实现时先入一个最大值元素,放在下标为0的地方,此后,元素从下标为1 的地方进行建堆,假设父节点下标是 i,则左右子节点 是2*i,2*i+1;
class Priority_ueue private: int heap_size; vector<int>heap; public: Priority_ueue() heap.push_back(INT_MAX); heap_size = 0; void insert(int num) heap.push_back(num); ++heap_size; int tmp = heap_size; for(;num > heap[tmp/2];tmp /= 2) heap[tmp] = heap[tmp/2]; heap[tmp] = num; //上滤 int delmax() if(heap_size == 0) cout << "delmax error!" << endl; return INT_MAX; else int res = heap[1]; int num = heap[heap_size--]; heap.pop_back(); int pos = 1, tmp = pos*2; while(tmp < heap_size) if(tmp+1 <= heap_size) tmp = heap[tmp] > heap[tmp+1] ? tmp : tmp + 1; if(num < heap[tmp]) heap[pos] = heap[tmp]; pos = tmp; tmp *= 2; else break; //下滤 heap[pos] = num; return res; bool empty() return heap_size == 0; int size() return heap_size; ;
测试样例:
int main() int tmp; Priority_queue q; while(cin >> tmp) q.insert(tmp); while(!q.empty()) cout << q.delmax() << endl; return 0;
floyd算法:
自下而上的、下滤操作:对所有的节点进行一次下滤, 每个节点下滤所需的时间正比于其高度,故总体运行时间取决于高度总和;相较于蛮力算法,深度小的节点远远少于高度小的节点;
建堆,以及对堆排序
建堆,以及堆排序
代码1:
#include<stdio.h> int h[101];//用来存放堆的数组 int n;//用来存储堆中元素的个数,就是堆的大小 //交换函数,用来交换堆中的俩个元素的值 void swap(int x,int y) { int t; 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[t]>h[i*2+1]) { t=i*2+1; } } //假设发现最小的结点编号不是自己,说明子结点中有比父节点更小的值 if(t!=i) { swap(t,i);//交换他们。注意swap函数 i=t;//更新i为刚才与它交换的儿子结点的编号。便于接下来继续向下调整 } else { flag=1; //否则说明当前的父结点已经比俩个子结点都要小了,不须要再进行调整 } } } //建立堆函数 void creat() { int i; for(i=n/2;i>=1;i--) { //总最后一个非叶结点到第一个结点一次进行向上调整 siftdown(i); } } //删除最大的元素 int deletemax() { int t; t=h[1];//用一个暂时变量记录堆顶点的值 h[1]=h[n];//将堆的最后一个点赋值给堆顶 n--;//堆的元素降低1 siftdown(1);//向下调整 return t;//返回之前记录的堆的顶点的最大值 } int main() { int i,num; scanf("%d",&num); for(i=1;i<=num;i++) { scanf("%d",&h[i]); } n=num; creat(); for(i=1;i<=num;i++) {//删除顶部元素,连续删除n次,事实上也就是从大到小的把数输出 printf("%d ",deletemax()); } return 0; }代码,2:
#include<stdio.h> int h[101]; //用来存储堆的数组 int n;//用来存储堆中的元素的个数,也就是堆的大小 //交换函数,用来交换堆中的俩个元素的值 void swap(int x,int y) { int t; 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[t]<h[i*2+1]) { t=i*2+1; } } //假设发现最小的结点编号不是自己,说明子结点中有比父节点更小的值 if(t!=i) { swap(t,i);//交换他们,注意swap函数 i=t;//更新i为刚才与它交换的儿子结点的编号。便于接下来继续向下调整 } else { flag=1; //否则说明当前的父结点已经比俩个子结点都要小了,不须要再进行调整 } } } //建立堆函数 void creat() { int i; 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); for(i=1;i<=num;i++) { scanf("%d",&h[i]); } n=num; creat();//建堆 heapsort();//堆排序 for(i=1;i<=num;i++) { printf("%d ",h[i]); } return 0; }
以上是关于自建堆排序:的主要内容,如果未能解决你的问题,请参考以下文章