根据维基百科的定义:
插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。
归并排序进行如下迭代操作:首先将原始序列看成 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
思路:如果是插入排序的话,那么就会b就会先有一段非递减序列,假设非递减序列到下标为j结束,那么数组b从下标j+1到n-1的数和原数组a一样。如果不是这样的话就是归并排序。
对插入排序来说,找到异常的数的下标,然后从这个下标开始往前走,如果找到比他小的数就把他放在比他小的数后面结束,如果这个数比他大,就把这个数往后挪。
对归并排序来说,找到头两个非递减序列的长度cnt1和cnt2,因为归并排序每次是两个和两个序列合并,所以取他俩的最小值cnt之后找一下能够两两配对的下标最长到哪,假设到x,然后我们对这两两配对的区间进行排序,最后处理一下最后没被配对的序列排个序就好了。
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int a[105];
int b[105];
int main(){
int n,x;//用x来记录异常顺序的数
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
cin>>b[i];
}
bool f=true;
int idx;//用idx来记录异常顺序数的下标
for(int i=0;i<n;i++){
if(b[i]<b[i+1])continue;//如果正常,直接跳过
else{
idx=i+1;//否则记录一下异常数的下标和数
x=b[i+1];
break;
}
}
for(int i=idx;i<n;i++){//检查异常数后面的数是否和原数组后面的数一样
if(a[i]!=b[i]){//如果不一样就是归并排序
f=false;
break;
}
}
if(f){
printf("Insertion Sort\n");
for(int i=idx;i>=0;i--){//如果是插入排序的话就从异常的数开始往前看
if(i==0)b[i]=x;//如果走到首个元素了就把异常元素放进首个元素里
else{
if(x>b[i-1]){//找到比异常元素小的位置,把异常元素放他后面
b[i]=x;
break;
}else{
b[i]=b[i-1];//如果他比异常元素大,把他往后挪
}
}
}
for(int i=0;i<n;i++){
if(i!=0)printf(" ");
printf("%d",b[i]);
}
}
else{
printf("Merge Sort\n");
int cnt1=1,cnt2=1,cnt,z=0;//cnt1是第一个非递减序列的长度,cnt2是第二个递减序列的长度
int flag=0;//记录是在算第一个长度还是第二个长度
for(int i=1;i<n;i++){
if(flag==0){//如果在算第一个长度
if(b[i-1]<=b[i]){//当他递增的时候长度++
cnt1++;
}else{//否则的话开始第二个长度的计算
flag=1;
}
}else{//第二个长度计算
if(b[i-1]<=b[i]){//如果递增长度就++
cnt2++;
}else break;//否则结束运算
}
}
cnt=min(cnt1,cnt2);//取两个序列最短的那个长度
int x=n/(2*cnt)*(2*cnt);//这里是在计算当前面的序列两两配对后的长度(
while(z+2*cnt<=n){//这个z是用来记录每次排序的头下标,这个操作是用来对两两配对的序列进行整合排序
sort(b+z,b+z+2*cnt);//将两两配对的区间里的数划分在一起排序
z+=2*cnt;//更新排序的下标
}
sort(b+x,b+n);//对最后没有配对的序列进行排序
for(int i=0;i<n;i++){
if(i!=0)printf(" ");
printf("%d",b[i]);
}
}
return 0;
}