一、概述
给出初始序列和进行一些步骤后的序列,让你判断进行的这一些步骤是插入排序还是堆排序。
判断之后输出下一步的序列。
主要考察插入排序和堆排序的实现。
二、分析
首先考虑插入排序。
令第一次排序后前一个元素有序,偷鸡方法是使用sort,直接对前n个元素排序就是第n次的插入排序结果。
如果乖乖的按插入排序做,就是像我下面这样:
for(int i=1;i<N;i++)
{
for(int j=i-1;j>=0;j--)
{
if(insert[j]>insert[j+1])
{
swap(insert[j],insert[j+1]);
}
else
break;
}
}
外层循环从1到N,内层循环从0到i-1。
比如说第i层循环,看第i个数,如果它比它前一个数小,那么掉换他俩位置,然后再判断。直到它不比它前面一个数小,这时break即可。这样就完成了一次插入排序。
重头戏在于堆排序。
堆排序分两步:
1、建堆
2、排序
首先注意要求,建的是大顶堆还是小顶堆。这关系到向下调整函数该怎么写。这里是建大顶堆。
比如说要求你从小到大排列,那就建大顶堆,从大到小就建小顶堆。
然后是核心的调整函数,如下:
void downAdjust(int low,int high)
{
int i=low,j=i*2;
while(j<=high)
{
if(j+1<=high&&heap[j]<heap[j+1])
j=j+1;
if(heap[i]<heap[j])
{
swap(heap[i],heap[j]);
i=j;
j=i*2;
}
else
break;
}
}
函数的两个参数分别是“目前要调整的节点”,“尾节点”。
首先进行初始化操作,设置i为“当前调整节点”,j为i的左孩子。注意整个函数是一个大循环,因此i会不断变化,目前要调整的节点只是当前调整节点的起点而已。不要弄混了。
然后进入循环,循环退出条件是i没有孩子或者不必调整了,在本题中就是剩下的已经是一个大顶堆了。
由于之前我们直接设置j为左孩子,那么现在判断i有没有右孩子,如果有而且右孩子大于左孩子,那么就令j加一。
现在可以看出来,j实际上是i的孩子中较大的那个。这样写既方便又简洁。
然后判断j对应的值是否大于i的,如果大于,就掉换他俩的值,如果不大于,那就退出循环。
很简洁,要记住。
这个函数说白了,实现的就是一次从上往下的调整,而建堆操作和排序操作,就是由许许多多的调整组成的。
下面看建堆。
for(int i=N/2;i>=1;i--)
{
downAdjust(i,N);
}
十分简单。
对于一给定的序列,对其进行建堆操作就是从它的N/2处开始,往前进行向下调整操作。
为什么从N/2处开始呢?因为只有从N/2处开始才有孩子。没孩子自然不用调整。
然后一点一点向上,最后调整到最上面的。因此循环条件如上。
然后就是排序了。
for(int i=N;i>=1;i--)
{
swap(heap[1],heap[i]);
m--;
downAdjust(1,m);
}
注意这是大顶堆,每次都可以选出一个最大值,那么我们把最大值放到最后,最后的值放到顶上,然后再次向下调整不就结了。
三、总结
学习如何建堆以及如何进行堆排序。
PS:代码如下:
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<unordered_map>
using namespace std;
int insert[110];
int heap[110];
int result[110];
//建小顶堆
/*void downAdjust(int low,int high)
{
int i=low,j=i*2;
while(j<=high)
{
if(j+1<=high&&heap[j]>heap[j+1])
j=j+1;
if(heap[i]>heap[j])
{
swap(heap[i],heap[j]);
i=j;
j=i*2;
}
else
break;
}
}*/
//建大顶堆
void downAdjust(int low,int high)
{
int i=low,j=i*2;
while(j<=high)
{
if(j+1<=high&&heap[j]<heap[j+1])
j=j+1;
if(heap[i]<heap[j])
{
swap(heap[i],heap[j]);
i=j;
j=i*2;
}
else
break;
}
}
int main()
{
int N;
scanf("%d",&N);
for(int i=0;i<N;i++)
{
int a;
scanf("%d",&a);
insert[i]=a;
heap[i+1]=a;
}
for(int i=0;i<N;i++)
scanf("%d",&result[i]);
//首先插入排序
//3128759460
//1328759460
//1238759460
//1237859460
int flagi=0;
int now=0;
for(int i=1;i<N;i++)
{
for(int j=i-1;j>=0;j--)
{
if(insert[j]>insert[j+1])
{
swap(insert[j],insert[j+1]);
}
else
break;
}
if(flagi==1)
{
printf("Insertion Sort\n");
int num=0;
for(int j=0;j<N;j++)
{
printf("%d",insert[j]);
num++;
if(num<N)
printf(" ");
}
return 0;
}
now=0;
for(int j=0;j<N;j++)
{
if(insert[j]!=result[j])
{
break;
}
else
now++;
}
if(now==N)
{
flagi=1;
}
}
//堆排序
//建堆
int flagh=0;
int nowh=0;
int m=N;
for(int i=N/2;i>=1;i--)
{
downAdjust(i,N);
}
for(int i=N;i>=1;i--)
{
swap(heap[1],heap[i]);
m--;
downAdjust(1,m);
nowh=0;
if(flagh==1)
{
printf("Heap Sort\n");
int num=0;
for(int j=1;j<=N;j++)
{
printf("%d",heap[j]);
num++;
if(num<N)
printf(" ");
}
return 0;
}
for(int j=1;j<=N;j++)
{
if(result[j-1]!=heap[j])
break;
else
nowh++;
}
if(nowh==N)
flagh=1;
}
}