本题目要求读入N个整数,采用堆排序法进行排序,输出前3轮排序后的结果。
输入格式:
输入不超过100的正整数N和N个整数(空格分隔)。
输出格式:
输出三行,第一行为第一轮排序结果,第二行为第二轮排序结果,第三行为第三轮排序结果。数据间用一个空格分隔。
为简便起见,最后一个元素后也有一个空格。
输入样例:
5
3 1 2 5 4
输出样例:
3 4 2 1 5
1 3 2 4 5
2 1 3 4 5
Ciallo~(∠・ω< )⌒★
思路:
这道题是最近学的排序方法中的一个,个人非常喜欢堆排序,因为在几个基本排序算法里堆排序算是比较快的,而且应用到了前些时候学到的树的思想。
首先,堆排序需要先将给出的数据按顺序构成一棵完全二叉树,按题目里给出的输入样例的话,就是像这样构造一个:
然后接下来是第一步
堆的初始化:
从定义上说,我们要构造一个大根堆,顾名思义,大根堆就是根结点的数值比较大,接着在各子树上都是父节点比子节点要大,这样依次传递。构造的过程需要先从完全二叉树的最后一个非叶节点开始找起,依次比较它与它的子节点的大小,然后将两个子节点中最大的数值上浮到父节点的位置。简单来说,就是把这个树里面沉在底部的大结点都上浮到上层,就像筛沙子一样,根据上面已经构造好的树来说,我们的初始堆化的过程如下:
到此,初始堆化完毕,值得一提的是,初始堆化并不能算作堆排序的排序过程,它只是首先构建了一个堆,后面的步骤才能算作是堆排序,所以我们不能将刚刚得到的5 4 2 1 3输出。
当然,初始堆化的过程我们可以写一个函数用来实现这个功能:
//函数中的a[]是存放需要排序数据的数组,i是根数据所在的数组下标,j是数组下标的上届
void heapify(int a[],int i,int j)
{
int k,x;
k=2*i;
x=a[i];
while(k<=j)
{
if(k<j)
if(a[k]<a[k+1])
k=k+1;
if(x>=a[k])
break;
else
{
a[i]=a[k];
i=k;
k=2*i;
}
}
a[i]=x;
}
接下来就是堆排序的过程:
堆排序:
堆排序的过程是将我们得到的大根堆变成数据从小到大排列的过程,这个过程里面,怎么将本来在上面的最大数值移到最后呢?很简单,只要将根从数组最开始和数组最末尾的数据交换即可,然后我们重新堆化除刚刚移过去的根以外的所有数据,这样就又能得到一个除去了刚刚最大数值的一个大根堆(也可以说,我们缩小了堆的范围)。这样,就算做堆排序的一轮排序完成,接下来我们只要重复有限次以上步骤,就可以完成对数据的排序。
简单的堆排序过程如下,我省略了重新堆化的详细步骤,和上面的过程并无二异:
我们可以看到,第一轮,第二轮,第三轮排序结果,与我们的输出样例完全相同,那么,这个过程就是正确的,接下来是要怎么用代码来实现它:
//数组a[]存储原始数据,n是数组下标上届(数据个数)
void heap_sort(int a[],int n)
{
int i,x,k=0;
for(i=n/2;i>=1;i--)
heapify(a,i,n);//初始堆化,循环是需要进行多次下沉操作(一个节点最多下沉n/2次)
for(i=n;i>1;i--)
{
x=a[1];
a[1]=a[i];
a[i]=x;
for(int I=1;I<=n;I++)
{
printf("%d ",a[I]);
}
printf("\n");//输出每一轮排序后的序列
heapify(a,1,i-1);//重新堆化
}
}
那么,这个代码已经非常简单的呈现在我们面前了,接下来只需要根据题目要求做出一点细节修改就可以了。
代码:
#include<stdio.h>
#define N 100//题目要求不超过100个数
void heapify(int a[],int i,int j)
{
int k,x;
k=2*i;
x=a[i];
while(k<=j)
{
if(k<j)
if(a[k]<a[k+1])
k=k+1;
if(x>=a[k])
break;
else
{
a[i]=a[k];
i=k;
k=2*i;
}
}
a[i]=x;
}
void heap_sort(int a[],int n)
{
int i,x,k=0;
for(i=n/2;i>=1;i--)
heapify(a,i,n);
for(i=n;i>1;i--)
{
x=a[1];
a[1]=a[i];
a[i]=x;
if(k<3)//题目要求前三次排序输出
{
for(int I=1;I<=n;I++)
{
printf("%d ",a[I]);
}
printf("\n");
k++;//k计数器
}
heapify(a,1,i-1);
}
}
int main()
{
int a[N],n,i;
scanf("%d",&n);
for(i=1;i<=n;i++)//注意,因为我们构造的是树,有父节点有子节点,不能用数组第一位a[0]存放数据
{
scanf("%d",&a[i]);
}
heap_sort(a,n);
}
看的出来,代码确实很简单。那么,各位小土豆们应该会有更好的思路,可以互相学习一下。
でわ、終わります。