堆排序
#include<iostream> //小顶堆
using namespace std;
int list[100];
void heappass(int list[],int i,int m) //i是根结点的编号,m是以i根结点的子树的最后一个结点编号,调整这棵子树为堆
{
int j=2*i,x=list[i];
while(j<=m) //这里j==m的情况(只有一个左孩子)也应考虑进去
{
if(j<m&&list[j]>list[j+1]) //若有两个孩子结点,则要list[j]是其中的较小值
j=j+1;
if(list[j]>x) //说明已经是堆,退出
break;
//if(list[j]>x)可以看出,每次都只是与原来的根结点作比较,因为
//在调整过程中除了要调整的根结点i外,以i之后的根结点的子树都已经是堆了,在下面的主体算法的初始堆中是从n/2倒着循环到1
else
{
list[i]=list[j];i=j;j=2*i; //继续向下搜索
}
}
list[i]=x; //插入x
}
void heapsort(int list[],int n) //从list[1]到list[n]
{
for(int i=n/2;i>=1;--i)
heappass(list,i,n);
//n其实不是以i根结点的子树的最后一个结点编号,但在heappass()函数内当i变成叶子结点的下标时,继续向下搜索,j=2*i;
//j一定会大于n,所以不用具体算出每个根结点的子树的最后一个结点编号
for(int i=n-1;i>=1;--i)
{
cout<<list[1]<<" ";
list[1]=list[i+1]; //把堆尾元素移到堆顶
heappass(list,1,i); //恢复堆,除根结点1的树外,其他都已是堆
//这里就不能heappass(list,1,n);每次的堆尾结点事实上并未删除,堆的结点个数一直没变
}
cout<<list[1]<<endl;
}
void main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>list[i];
heapsort(list,n);
}
/*
8
46 55 13 42 94 17 5 80
*/