该题是默认递增排序的,以下不再赘述。
- 如何判断是归并排序还是插入排序呢
样例
10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0
插入排序
3
1 3
1 2 3
1 2 3 8
1 2 3 7 8 (5 9 4 6 0)
样例只进行到了这一步,我们可以很清楚的发现,前面1~8是已经进行完插入排序的,前一部分保持递增有序,后面部分与原序列完全相同
这就是插入排序的特点:前一部分保持递增有序,后面部分与原序列完全相同
那么我们就需要找分成两部分的位置是哪里,如果不存在这个位置,那么就是归并排序。
归并排序是分组递归进行排序,于是乎我们就会有那么一个问题,当前数组是在第几次归并后的结果,此时的分组大小是多少呢?是每组两个、还是每组三个?亦或者是其他呢
这里的解决办法就是,我们从 原数组 进行 归并排序直到归并内容等于当前数组,然后再进行一次归并就结束。
接下来的问题在于怎么写方便,我们的递归是分两个分两个的,那么我们排序最小组的长度就为2,然后是4,每次乘2
拿例子来说
数组下标
len = 2:(12)(34)(56)(78)(910)
len = 4: (1234) (5678)(910)
len = 8:。。。
综上,写个循环即可实现。
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 111;
int a[maxn], b[maxn];
int ma[maxn];
int n;
//bool onetap = true;
void slove_merge(){
bool flag = true;
int k = 1;
while(flag){
//直到原数组与当前相同,然后再进行一次归并
flag = false;
for(int i = 1; i <= n; i++){
if (a[i] != b[i]) {
flag = true;
}
}
k *= 2;
//分组排序,从每组长度为2开始
for(int i = 0; i < n / k; i++){
sort(a + i * k + 1, a + (i + 1) * k + 1);
}
sort(a + (n / k) * k + 1, a + n + 1);
}
for(int i = 1; i <= n; i++){
i == 1 ? printf("%d", a[i]) : printf(" %d", a[i]);
}
}
int main(){
cin >> n;
int flag = -1;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n; i++){
cin >> b[i];
if (b[i] < b[i - 1] && flag == -1){
flag = i;
}
}
bool ins = true;
for(int i = flag; i <= n; i++){
if (a[i] != b[i]){
ins = false; //说明不是插入排序
break;
}
}
if (ins) {
printf("Insertion Sort\n");
//将下一位置的值移入前面有序中,且保持前一部分继续有序
sort(b + 1, b + flag + 1);
for(int i = 1; i <= n; i++){
i == 1 ? printf("%d", b[i]) : printf(" %d", b[i]);
}
}
else {
printf("Merge Sort\n");
slove_merge();
}
}