根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 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
代码如下:(有详解)
#include<stdio.h>
#include<stdlib.h>
/* 判断是否是插入排序 */
int IsInsertion(int *a, int *b, int N){
int i,k;
/* 找到非有序序列第一个元素的位置 */
for(i=1;i<N;i++)
if(b[i]<b[i-1]) break;
k = i; //用 k 储存非有序序列第一个元素位置
/* 判断数组a[]和b[]剩下的序列是否一致,一致的话证明是插入排序,否则是归并排序 */
for(;i<N;i++)
if(b[i]!=a[i]) break;
if(i==N) return k; //是插入排序的话返回非有序序列第一个元素的位置
else return 0; //返回0表示不是插入排序
}
/* 输出结果的函数 没什么好说的 */
void PrintResults(int *b, int N){
int i;
printf("%d",b[0]);
for(i = 1;i<N;i++){
printf(" %d",b[i]);
}
printf("\n");
}
/* 插入排序再迭代一轮的结果 */
void NextInsertion(int *b,int N, int k){ //传入的 k 就是插入排序未排序序列第一个元素的位置
int i,tmp;
printf("Insertion Sort\n");
tmp = b[k];
/* 迭代一轮把tmp插入到有序序列中 */
for(i = k-1;i>=0;i--){
if(tmp<b[i]) b[i+1] = b[i];
else break;
}
b[i+1] = tmp;
PrintResults(b ,N);
}
/* 判断归并排序当前的归并长度 (划重点了!) */
/* 该方法来自陈越姥姥 */
int MergeLength(int *b, int N){
int i, l;
/* 首先让当前归并长度为 2 ,随着归并次数的增加归并长度不断乘2*/
for(l = 2;l<=N;l*=2){
/* 判断每两个归并段相邻的那两个元素是否有序 */
/* 如先比较归并段1,2相邻的元素(即归并段1的最后一个元素与归并段2的第一个元素), 再去比较归并段3,4相邻的元素,以此类推 */
for(i = l;i<N;i+=(l+l))
if(b[i-1]>b[i]) break; //找到了不符合条件的元素,此时l 就是当前归并长度
if(i<N) break;
}
return l;
}
/* 归并排序再迭代一轮的结果 */
void NextMerge(int *b, int N){
int i,p1,p2,p,L;
int *tmp;
/* tmp[]是一个临时数组 */
tmp = (int *)malloc(sizeof(int)*N);
printf("Merge Sort\n");
L = MergeLength(b, N); //L储存当前的归并长度
p = 0; //p指向tmp[]中当前处理的位置
/* 开始归并 */
for(i =0;i<(N-L-L);i+=(L+L)){ //两两归并长度为L的段
/* p1, p2分别指向两个段当前的处理位置 */
p1 = i;
p2 = i+L;
/* 归并两个段,并把数据存入临时数组 tmp */
while((p1<(i+L))&&(p2<(i+L+L))){
if(b[p1]>b[p2])
tmp[p++] = b[p2++];
else
tmp[p++] = b[p1++];
}
/* 处理剩余元素 */
while(p1<(i+L))
tmp[p++] = b[p1++];
while(p2<(i+L+L))
tmp[p++] = b[p2++];
}
/* 如果最后剩两段,执行归并 */
if((N-i)>L){
p1 = i;
p2 = i+L;
while(p1<(i+L)&&p2<N){ //注意这段代码与上面一段代码的区别就在于第二段的结束条件
if(b[p1]<b[p2])
tmp[p++] = b[p1++];
else
tmp[p++] = b[p2++];
}
while(p1<(i+L)) tmp[p++] = b[p1++];
while(p2<N) tmp[p++] = b[p2++];
}
/* 最后只剩一段时直接存入临时数组 */
else
while(i<N) tmp[p++] = b[i++];
PrintResults(tmp, N);
}
int main(void){
int N,i,k;
int *a, *b;
scanf("%d",&N);
a = (int *)malloc(sizeof(int)*N); //数组a[]储存原始序列
b = (int *)malloc(sizeof(int)*N); //数组b[]储存中间序列
for(i =0;i<N;i++)
scanf("%d",&a[i]);
for(i =0;i<N;i++)
scanf("%d",&b[i]);
if(k =IsInsertion(a, b, N)){
NextInsertion(b, N, k);
}else{
NextMerge(b ,N);
}
return 0;
}