该排序首先要建立堆以建立最小堆为例,在建立堆的时候用到了向下调整的思想,即该点如果的值a[i],如果小于a[2*i]或a[2*+1],则需要把a[i]与a[2*i]和a[2*+1]的较小者交换,以达到上小下大,需要注意的是在建立最小堆的时候要从后往前建立,也就是最后一个非叶子节点开始建立,即a[n/2],因为这样可以达到下面的数都比上面的数大(如果从根开始建堆的话,可能会出现最下面的数很小,但是中间的数较大,然后中上的数又较小,而最上面的数很大,这样一来,最上面的数与中上换过之后不能与中间的数交换,以导致最下面的最小数无法换到上面,下面给的样例就是这样的)
样例输入:
14
99 5 36 7 22 17 46 12 2 19 25 28 1 92
样例输出:
1 2 5 7 12 17 19 22 25 28 36 46 92 99
代码:
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[110];
int n;
void siftdown(int i);//向下调整
int main()
{
int i,j,maxn=-1;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]>maxn)
maxn=a[i];
}
for(i=n/2;i>=1;i--)//建立堆
siftdown(i);
for(i=1;i<=n;i++)
{
printf("%d ",a[1]);
a[1]=maxn;
siftdown(1);
}
printf("\n");
return 0;
}
void siftdown(int i)//最小堆
{
int t,flag=0,temp;
while(2*i<=n&&flag==0)
{
t=i;
if(a[t]>a[2*i])
t=2*i;
if(2*i+1<=n&&a[t]>a[2*i+1])
t=2*i+1;
if(t!=i)
{
temp=a[i];
a[i]=a[t];
a[t]=temp;
i=t;
}
else
flag=1;
}
}
在从小到大排序过程,更多的用的是建立最大堆,因为最大堆中最上面就是最大的数,然后把a[1]和a[n]交换,此时a[n]就是最大的数了,然后将堆的大小减1,即n--,还需要把a[1]进行向下调整,以保持堆的特征,循环操作,直到堆为空即可,当然了,你可能会问建立最小堆为什么不这样操作呢,其实也可以,你可以试试,之所以用最大堆,我感觉是因为在排完序之后输出很方便,直接把数组从1到n输出即可
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[110];
int n;
void siftdown(int i);//向下调整
int main()
{
int i,j,t;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=n/2;i>=1;i--)//建立堆
siftdown(i);
t=n;
while(n>1)//最后一个就不用排了吧,所以是n>1
{
swap(a[1],a[n]);
n--;
siftdown(1);
}
for(i=1;i<=t;i++)
printf("%d ",a[i]);
printf("\n");
return 0;
}
void siftdown(int i)//最大堆
{
int t,flag=0,temp;
while(2*i<=n&&flag==0)
{
t=i;
if(a[t]<a[2*i])
t=2*i;
if(2*i+1<=n&&a[t]<a[2*i+1])
t=2*i+1;
if(t!=i)
{
temp=a[i];
a[i]=a[t];
a[t]=temp;
i=t;
}
else
flag=1;
}
}