思路:
堆排序利用大根堆的特性,即根节点为最大值,每一次将根节点移到数组后面,相当于每一次都在把大的值往后放,同时我们所需要考虑的范围也在不断减小,相当于分别在0 ~ last ,0 ~ last-1 , 0 ~ last-2,…0~1中找最大值
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
//n是总结点数,x是当前需要堆化的结点
void singleheapify(int a[],int last,int x)//对一个结点进行堆化
{
int max = x;//max存放(x和他的儿子共3个结点)全家人中的最大值
int lch=2*x+1;//左儿子刚好就是这个
int rch=2*x+2;//右儿子刚好就是这个
if(a[max]<a[lch]&&lch<=last) max = lch;
if(a[max]<a[rch]&&rch<=last) max = rch;//这一步千万千万不要加else
/*结合上一步的if,这两个if其实是在找x和儿子三个人之间的最大值,找到了再去交换,
否则我们交换了一边,另一边可能是不满足父亲值最大的*/
if(max != x)//儿子比父亲大,要交换
{
swap(a[max],a[x]);
singleheapify(a,last,max);/*以当前max指向的下标为父亲,
继续看看符不符合大根堆的要求*/
}
}
void allheapify(int a[],int last)//全部节点堆化
{
int lastparent = (last-1) / 2;//找到最后一个非叶子节点的下标
//从最后一个非叶子节点开始枚举,在这之前的结点全是有儿子的结点
for(int j=lastparent;j>=0;j--)singleheapify(a,last,j);
}
void heapsort(int a[],int last)//堆排序重点部分!!!!!
{
allheapify(a,last);//把原数组堆化,使其各节点都满足堆的要求
for(int i=last;i>=1;i--)//枚举大根堆的最后一个结点,一直枚举直到1就结束,//
{ /*大根堆在不断减小,
相当于分别在0~last,0~last-1,0~last-2,......0~1中找最大值,
每一次将所找到的最大值放到数组后面*/
for(int j=0;j<=last;j++) printf("%d ",a[j]);cout<<endl;
swap(a[0],a[i]);/*生成了一个大根堆因此具有根节点值最大的性质,
利用这个性质我们把根节点放数组最后*/
singleheapify(a,i-1,0);/*,当前根节点已经发生变化,
即不是最大值而是最后一个结点交换上来的,
结合上一步,这两步相当于把0~i范围内的最大值移出去,
减小大根堆规模,当前只考虑0~i-1范围内最大值,在新的范围里面再次构建大根堆*/
}
}
int main()
{
int n,a[500];
scanf("%d",&n);
for(int i=0;i<=n-1;i++) cin>>a[i];
heapsort(a,n-1);
for(int j=0;j<=n-1;j++) cout<<a[j]<<" ";
return 0;
}