堆排序
2017-10-30 09:37
204 查看
此文乃博主的朋友写的,在此十分感谢她
#include <cstdio>
int n,m,a[100005]; //建立大根堆,从小到大排序
void add(int x,int t) //往堆中添加节点
{
a[t]=x; //把新节点放在堆的最后
//整理堆,使堆始终保持大根堆的性质
while (t>1 && a[t/2]<a[t]) // 如果该节点不是堆的根,并且大于它的父亲节点,那么不符合大根堆的性质
{ //调整
int tt=a[t/2]; a[t/2]=a[t]; a[t]=tt; //和父亲节点交换
t/=2; //节点上移,继续调整
}
//因为只有当儿子节点大于父亲节点时才交换,所以最后新节点一定大于它的两个儿子节点
// 当新节点小于父亲节点时停止交换
//这样就保持了大根堆的性质
return;
}
void sort() //开始堆排
{ //每次把根和堆的最后一个节点交换
//就是把根取出,暂存在最后,然后整理堆中剩下的节点,找出剩余节点中最大的
//因为是大根堆,每次取出的根节点都是剩余节点中最大的
//所以下一次取出的节点肯定比上一次小
//每次都把取出的根节点放在当前堆的最后
//所以最后数组从后往前是递减的
//所以大根堆排序是从小到大的
int t;
while (m>1) //当堆中只剩下一个节点时,不用再整理了
{
int ls,rs,son,i=1;
// ls 左儿子下标
// rs 右儿子下标
//son 要和当前节点交换的儿子下标
while (i*2<=m) //儿子还在当前堆的范围内
{
ls=i*2; rs=ls+1; son=i;
if (a[ls]>=a[i]) //如果左儿子大于当前节点,交换
t=a[ls], a[ls]=a[i], a[i]=t, son=ls;
if (rs<=m && a[rs]>=a[i]) //如果左又儿子大于当前节点,且右儿子没有超出当前堆的范围,交换
t=a[rs], a[rs]=a[i], a[i]=t, son=rs;
if (i==son) //说明当前节点大于它的两个儿子节点
break; //结束
i=son; //如果没有结束,说明还需要交换,继续
}
int t=a[m]; a[m]=a[1]; a[1]=t; m--;
// 把根结点放在当前堆的最后 ,减小堆的范围
}
return;
}
int main()
{
int i,j,x;
scanf("%d",&n);
scanf("%d",&a[1]);
for (i=2;i<=n;i++)
{
scanf("%d",&x);
add(x,i);
}
8bcf
//添加完节点的堆是一个大根堆
int t=a
; a
=a[1]; a[1]=t; m=n-1;
// 把根结点放在当前堆的最后 ,减小堆的范围
sort();
for (i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}
#include <cstdio>
int n,m,a[100005]; //建立大根堆,从小到大排序
void add(int x,int t) //往堆中添加节点
{
a[t]=x; //把新节点放在堆的最后
//整理堆,使堆始终保持大根堆的性质
while (t>1 && a[t/2]<a[t]) // 如果该节点不是堆的根,并且大于它的父亲节点,那么不符合大根堆的性质
{ //调整
int tt=a[t/2]; a[t/2]=a[t]; a[t]=tt; //和父亲节点交换
t/=2; //节点上移,继续调整
}
//因为只有当儿子节点大于父亲节点时才交换,所以最后新节点一定大于它的两个儿子节点
// 当新节点小于父亲节点时停止交换
//这样就保持了大根堆的性质
return;
}
void sort() //开始堆排
{ //每次把根和堆的最后一个节点交换
//就是把根取出,暂存在最后,然后整理堆中剩下的节点,找出剩余节点中最大的
//因为是大根堆,每次取出的根节点都是剩余节点中最大的
//所以下一次取出的节点肯定比上一次小
//每次都把取出的根节点放在当前堆的最后
//所以最后数组从后往前是递减的
//所以大根堆排序是从小到大的
int t;
while (m>1) //当堆中只剩下一个节点时,不用再整理了
{
int ls,rs,son,i=1;
// ls 左儿子下标
// rs 右儿子下标
//son 要和当前节点交换的儿子下标
while (i*2<=m) //儿子还在当前堆的范围内
{
ls=i*2; rs=ls+1; son=i;
if (a[ls]>=a[i]) //如果左儿子大于当前节点,交换
t=a[ls], a[ls]=a[i], a[i]=t, son=ls;
if (rs<=m && a[rs]>=a[i]) //如果左又儿子大于当前节点,且右儿子没有超出当前堆的范围,交换
t=a[rs], a[rs]=a[i], a[i]=t, son=rs;
if (i==son) //说明当前节点大于它的两个儿子节点
break; //结束
i=son; //如果没有结束,说明还需要交换,继续
}
int t=a[m]; a[m]=a[1]; a[1]=t; m--;
// 把根结点放在当前堆的最后 ,减小堆的范围
}
return;
}
int main()
{
int i,j,x;
scanf("%d",&n);
scanf("%d",&a[1]);
for (i=2;i<=n;i++)
{
scanf("%d",&x);
add(x,i);
}
8bcf
//添加完节点的堆是一个大根堆
int t=a
; a
=a[1]; a[1]=t; m=n-1;
// 把根结点放在当前堆的最后 ,减小堆的范围
sort();
for (i=1;i<=n;i++)
printf("%d ",a[i]);
return 0;
}