1089. Insert or Merge (25) - PAT甲级真题

该题是默认递增排序的,以下不再赘述。

  • 如何判断是归并排序还是插入排序呢

样例
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();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值