首页 > 代码库 > 堆排序
堆排序
N个元素称为堆,若它的元素序列k[1],k[2],k[3].....K[n]满足
k[i]<=k[2i] ,k[i]<=k[2i+1] 1<=i<=n/2
则称之为最小堆(min_heaps), 如果满足
k[i]>=k[2i] ,k[i]>=k[2i+1] 1<=i<=n/2
则称之为最大堆(min_heaps)。
================
下面左边的图表示最大堆,右边表示堆在数组中的存取情况
下面以最大堆为例,说明堆的操作。
一:堆的上移动操作
如果修改堆中某个元素,使得它的值大于父节点的,这就破坏了最大堆的性质,因此需要对堆实现上移操作。
//对下标为i的数进行上移动操作,flag标记修改后的值是否大于父节点 void sift_up(int *H,int i) { bool flag=true; while(flag &&i!=1) { if(H[i]>H[i/2]) swap(H[i],H[i/2]); else flag=false; i=i/2; } }
二:堆的下移操作
如果修改堆中某个元素,使得它的值小于孩子节点,这就破坏了最大堆的性质,因此需要对堆实现下移操作。
//形参m为堆元素个数 void sift_down(int *H,int m,int i) { bool flag=true; while(flag && (i=2*i)<=m) { if(i+1<=m && H[i+1]>H[i]) //选取需要下移的节点的左右孩子节点中较大的那个元素 i++; if(H[i]>H[i/2]) //此时的i/2即为我们需要下移的元素,如果它比它的左右孩子节点中较大的那个要小,那么两者互换 swap(H[i],H[i/2]); else flag=false; } }
三:堆的删除操作
如果我们要删除下标为 i 的元素,那么我们可以用堆中最后1个元素替代i,然后对这个替代后的元素执行上移或者下移操作
//删除堆中下表为i的元素,最后元素个数由m带回 void heap_delete(int *H,int i ,int &m) { if(i>m) cout<<"overflow"<<endl; else { int a,b; a=H[i]; b=H[m]; H[i]=b; m--; if(a>b) { sift_down(H,m,i); } else { sift_up(H,i); } } }四:堆的插入操作
插入到堆最后1个元素后面,然后对该元素执行上移操作
//形参m为堆元素的个数,num为插入的数 void Insert(int *H,int &m,int num) { m++; H[m]=num; sift_up(H,m); }五:堆的建立
把要建立成堆的元素依次调用上面的插入函数,一个一个插入,就成了堆
// A为需要建立堆的数组,H为所建立的堆,g为A中的数组元素个数,m为堆的元素,最后该参数返回堆的元素个数 //堆是从H[1]开始存储元素 void make_heap(int *A,int *H,int g,int &m) { m=0; for(int i=0;i<g;i++) { Insert(H,m,A[i]); } }
六:堆的排序
假设堆有n个元素,由于堆的第一个元素一定是最大的元素,因此可以让第一个元素和第n个元素互换,然后对第一个元素执行下操作。接着,对n-1个元素执行相同的操作,让第一个元素与第n-1个元素互换,然后对第一个元素执行下移操作,依次类推,最后的堆就是从小到大排序好的堆。
//堆排序,m为堆的元素个数 void heap_sort(int *H,int m) { int i; for(i=m;i>0;i--) { swap(H[i],H[1]); sift_down(H,i-1,1); //注意第2个参数为i-1,不是m,是对接下来的i-1个堆元素进行操作 } }
完整的代码如下:
#include<iostream> using namespace std; void swap(int &a,int &b) { int c; c=a; a=b; b=c; } //对下标为i的数进行上移动操作 void sift_up(int *H,int i) { bool flag=true; while(flag &&i!=1) { if(H[i]>H[i/2]) swap(H[i],H[i/2]); else flag=false; i=i/2; } } //形参m为堆元素个数 void sift_down(int *H,int m,int i) { bool flag=true; while(flag && (i=2*i)<=m) { if(i+1<=m && H[i+1]>H[i]) //选取需要下移的节点的左右孩子节点中较大的那个元素 i++; if(H[i]>H[i/2]) //此时的i/2即为我们需要下移的元素,如果它比它的左右孩子节点中较大的那个要小,那么两者互换 swap(H[i],H[i/2]); else flag=false; } } //形参m为堆元素的个数,num为插入的数 void Insert(int *H,int &m,int num) { m++; H[m]=num; sift_up(H,m); } // A为需要建立堆的数组,H为所建立的堆,g为A中的数组元素个数,m为堆的元素,最后该参数返回堆的元素个数 //堆是从H[1]开始存储元素 void make_heap(int *A,int *H,int g,int &m) { m=0; for(int i=0;i<g;i++) { Insert(H,m,A[i]); } } //删除堆中下表为i的元素,最后元素个数由m带回 void heap_delete(int *H,int i ,int &m) { if(i>m) cout<<"overflow"<<endl; else { int a,b; a=H[i]; b=H[m]; H[i]=b; m--; if(a>b) { sift_down(H,m,i); } else { sift_up(H,i); } } } //堆排序,m为堆的元素个数 void heap_sort(int *H,int m) { int i; for(i=m;i>0;i--) { swap(H[i],H[1]); sift_down(H,i-1,1); //注意第2个参数为i-1,不是m,是对接下来的i-1个堆元素进行操作 } } void main() { int A[5]={34,11,242,22,4}; int H[6]; int m,i; make_heap(A,H,5,m); for(i=1;i<=m;i++) { cout<<H[i]<<" "; } cout<<endl; cout<<"上移操作:"<<endl; H[5]=999; sift_up(H,5); for(i=1;i<=m;i++) { cout<<H[i]<<" "; } cout<<endl; cout<<"下移操作:"<<endl; H[1]=1; sift_down(H,m,1); for(i=1;i<=m;i++) { cout<<H[i]<<" "; } cout<<endl; cout<<"元素删除操作,删除堆顶元素"<<endl; heap_delete(H,1,m); for(i=1;i<=m;i++) { cout<<H[i]<<" "; } cout<<endl; cout<<"堆排序:"<<endl; heap_sort(H,m); for(i=1;i<=m;i++) { cout<<H[i]<<" "; } cout<<endl; system("pause"); }
时间复杂度为O(nlogn)
堆排序
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。