堆排时间复杂度为O(n log n),比快排稳定
这次先贴代码emmm
下次有空再来补解析
自我感觉注释很详细了
1 #include <cstdio> 2 int n,m,a[5000005]; //建立大根堆,从小到大排序 3 void add(int x,int id) //往堆中添加节点 4 { 5 int fa; // 父节点 6 a[id]=x; //把新节点放在堆的最后 7 //整理堆,使堆始终保持大根堆的性质 8 while (id>1 && a[id/2]<a[id]) // 如果该节点不是堆的根,并且大于它的父亲节点,那么不符合大根堆的性质 9 { //调整 10 fa=id>>1; 11 a[fa]^=a[id]; a[id]^=a[fa]; a[fa]^=a[id]; //和父亲节点交换 12 id=fa; //节点上移,继续调整 13 } 14 //因为只有当儿子节点大于父亲节点时才交换,所以最后新节点一定大于它的两个儿子节点 15 //当新节点小于父亲节点时停止交换 16 //这样就保持了大根堆的性质 17 return; 18 } 19 void heapsort() //开始堆排 20 { 21 //每次把根和堆的最后一个节点交换 22 //就是把根取出,暂存在最后,然后整理堆中剩下的节点,找出剩余节点中最大的 23 //因为是大根堆,每次取出的根节点都是剩余节点中最大的 24 //所以下一次取出的节点肯定比上一次小 25 //每次都把取出的根节点放在当前堆的最后 26 //所以最后数组从后往前是递减的 27 //所以大根堆排序是从小到大的 28 while (m>1) //当堆中只剩下一个节点时,不用再整理了 29 { 30 int ls,rs,son,i=1; 31 // ls 左儿子下标 32 // rs 右儿子下标 33 // son 要和当前节点交换的儿子下标 34 while (i*2<=m) //儿子还在当前堆的范围内 35 { 36 ls=i<<1; rs=ls|1; 37 son=(rs<=m && a[rs]>a[ls])?rs:ls; // 找出两个儿子中较大的 38 if (a[i]>=a[son]) //说明当前节点大于它的两个儿子节点 39 break; //结束 40 a[i]^=a[son]; a[son]^=a[i]; a[i]^=a[son]; // 交换后父节点不小于两个子节点 41 i=son; //如果没有结束,说明还需要交换,继续 42 } 43 a[m]^=a[1]; a[1]^=a[m]; a[m]^=a[1]; m--; 44 // 把根结点放在当前堆的最后 ,减小堆的范围 45 } 46 return; 47 } 48 int main() 49 { 50 int i,j,x; 51 scanf("%d",&n); 52 scanf("%d",&a[1]); 53 for (i=2;i<=n;i++) 54 { 55 scanf("%d",&x); 56 add(x,i); 57 } 58 //添加完节点的堆是一个大根堆 59 a[n]^=a[1]; a[1]^=a[n]; a[n]^=a[1]; m=n-1; 60 // 把根结点放在当前堆的最后 ,减小堆的范围 61 heapsort(); 62 for (i=1;i<=n;i++) 63 printf("%d ",a[i]); 64 return 0; 65 }
测试了一下发现堆排的速度果然还是比不上C++的sort