题目
根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。
现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?
输入格式:
输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。
输出格式:
首先在第 1 行中输出Insertion Sort
表示插入排序、或Merge Sort
表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。
输入样例 1:
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
输出样例 1:
Insertion Sort
1 2 3 5 7 8 9 4 6 0
输入样例 2:
10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6
输出样例 2:
Merge Sort
1 2 3 8 4 5 7 9 0 6
AC代码
- 区分出中间序列是哪种排序算法产生的,其实只需判断“插入排序能否产生该中间序列”即可。如果插入排序可以产生,那么归并排序必然不能有该中间序列,因为如果归并排序也能产生该中间序列,那么两种排序都是可能的,无法判断准确结果,而题目保证不会有这种情况。既然题目保证了两种排序非此即彼,那么只判断一个更容易判断的插入排序即可。
- 从后往前逐一对比原始序列与中间序列,定位最后一个发生改变的数组元素。检测该元素之前的所有元素是否有序,若有序,则为插入排序;若不为有序,则为归并排序。
- 按中间序列的排序算法,用该算法迭代一次输出:根据插入排序的特点,若已排序前n个元素,迭代一次即将前n+1个元素排序即可;而归并排序,观察样例,是由循环实现的归并,需要处理小尾巴(每次迭代之后,每 2 n 2^n 2n个元素为有序,而末尾不足 2 n 2^n 2n个元素的元素集合是要特殊处理的小尾巴)。迭代一次不需要自己写相应的排序算法,按特点将特定元素用库函数qsort排序即可。
- 测试点2:对于例如
原始序列:1 9 5 4 10 11 8 中间序列:1 4 5 9 10 11 8
这类迭代次数不确定的插入排序(可以是迭代4次也可以是迭代5次、6次,第5,6次因为10,11插在原位置上,与不迭代的结果是一样的),题目是要求输出下一个与中间序列不同的结果。即输出:1 4 5 8 9 10 11
#include<stdio.h>
#include<stdlib.h>
int N,num1[100],num2[100];
int cmp(void *a,void *b){ //qsort回调函数
return *(int *)(a)-*(int *)(b);
}
int judge(){ //判断排序算法
int flag=0;
for(int i=N-1;i>=0;i--){ //定位最后一个发生改变的元素的位置
if(num1[i]!=num2[i]){
flag=i;
break;
}
}
for(int i=0;i<flag;i++){ //检查该元素之前的元素是否有序
if(num2[i]>num2[i+1]){
printf("Merge Sort\n"); //非有序则输出归并排序并返回1
return 1;
}
}
printf("Insertion Sort\n"); //有序则输出插入排序,顺便迭代一次
for(int i=flag;i<N;i++){ //因为测试点2的问题需要找到下一个逆序的元素,将其插入
if(num2[i]>num2[i+1]){
flag=i;
break;
}
}
qsort(num2,flag+2,sizeof(int),cmp);
return 0;
}
int main()
{
scanf("%d",&N);
for(int i=0;i<N;i++)
scanf("%d",&num1[i]);
for(int i=0;i<N;i++)
scanf("%d",&num2[i]);
if(judge()==1){ //若为归并排序,则迭代一次
for(int i=2;i<=N;i=i*2){
int lim=N/i*i,flag=0; //lim为去掉小尾巴的元素个数
for(int j=0;j<lim;j=j+i){ //在每2的i次方个元素中寻找逆序元素,标记
for(int k=j;k<j+i-1;k++){
if(num2[k]>num2[k+1]){
flag=1;
}
}
}
if(flag){ //被标记有逆序元素,将每2的i次方个元素进行排序作为一次迭代,并退出循环
for(int j=0;j<lim;j=j+i)
qsort(num2+j,i,sizeof(int),cmp);
if(lim<N)qsort(num2+lim,N-lim,sizeof(int),cmp); //若有小尾巴处理小尾巴
break;
}
}
}
printf("%d",num2[0]); //输出
for(int i=1;i<N;i++){
printf(" %d",num2[i]);
}
return 0;
}