题目传送门<==戳这
这道题考查对 插入(选择)排序 和 归并排序 “原理” 的掌握程度,如果只是背的模板,那这道题可能会超时或没思路。
原始序列==> a ,
某排序算法产生的中间序列==> b
关键点:
1.判断排序类型:
遍历b数组,第一次 b [ i ] > b [ i + 1 ] 的时候就是下一次插入排序的标志性位置;
然后对从 i+1 开始遍历,如果 a [ i ] == b [ i ] 直到最后都成立,说明是插入排序,反之为归并排序;
2.插入排序的下一个排序:
即加入后面一个元素进行排序
puts("Insertion Sort");
sort(b+1,b+1+id); ==>id是第一次 b [ i ] > b [ i + 1 ] 的时候 i+1 的值
printf("%d",b[1]);
for(int i=2;i<=n;i++) printf(" %d",b[i]);
这里暂时没看懂也没关系,后面看整体更清晰
3.归并排序的下一个排序
让 a 数组(即原序列数组)每次循环都模拟归并排序,再与 b 数组匹配
puts("Merge Sort");
int k=1; ==>k是归并排序的“规模”
while(1){
int i;
for(i=1;i<=n;i++){ ==>匹配过程,如果二者不完全相同,继续归并排序
if(a[i]!=b[i]){
break;
}
}
k*=2; ==>调整“规模”
int j;
for(j=0;j<n/k;j++){ ==>仔细琢磨一下,归并排序的分块排序思想
sort(a+1+j*k,a+1+(j+1)*k);
}
sort(a+1+j*k,a+1+n); ==>因为元素个数不一定是“规模”的整数倍,所以要对“尾巴”进行单独处理
if(i==n+1){ ==>如果两数组完全相同,则跳出循环
break; ==>这里特别注意这个判断并不是在排序代码的前面
==>因为是求下一个排序,所以制造完下一个排序后才跳出循环,仔细琢磨
}
}
printf("%d",a[1]);
for(int i=2;i<=n;i++){
printf(" %d",a[i]);
}
上完整代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=200;
int a[maxn],b[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
int sign=1,id;
==>判断排序类型
int i;
for(i=1;i<n;i++){
if(b[i]>b[i+1]){
id=i+1;
break;
}
}
int j;
for(j=i+1;j<=n;j++){
if(a[j]!=b[j]){
sign=0;
}
}
==>sign==1为插入排序
if(sign==1){
puts("Insertion Sort");
sort(b+1,b+1+id);
printf("%d",b[1]);
for(int i=2;i<=n;i++) printf(" %d",b[i]);
}else{
puts("Merge Sort");
int k=1;
while(1){
int i;
for(i=1;i<=n;i++){
if(a[i]!=b[i]){
break;
}
}
k*=2;
int j;
for(j=0;j<n/k;j++){
sort(a+1+j*k,a+1+(j+1)*k);
}
sort(a+1+j*k,a+1+n);
if(i==n+1){
break;
}
}
printf("%d",a[1]);
for(int i=2;i<=n;i++){
printf(" %d",a[i]);
}
}
}