1035 插入与归并 (25 分)

题干太长了,就不抄题干了,若要查看题干请点击本链接

分析:

题目是要判断一排数字是 插入排序 后的结果,或者是 归并排序 后的结果。

所以首先,我们要先搞清楚什么是插入排序,什么是归并排序。

这一点题目中有给到:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。

输入样例 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

对于题干中的输入样例1 : 3 1 2 8 7 5 9 4 6 0 进行插入排序,步骤如下:
step1:选3,新序列3 ,原始序列1 2 8 7 5 9 4 6 0
step2:选1,新序列1 3 ,原始序列2 8 7 5 9 4 6 0
step3:选2,新序列1 2 3 ,原始序列8 7 5 9 4 6 0
step4:选8,新序列1 2 3 8 ,原始序列7 5 9 4 6 0
step5:选7,新序列1 2 3 7 8 ,原始序列5 9 4 6 0
step6:选5,新序列1 2 3 5 7 8 ,原始序列9 4 6 0
step7:选9,新序列1 2 3 5 7 8 9 ,原始序列4 6 0
step8:选4,新序列1 2 3 4 5 7 8 9 ,原始序列6 0
......

可以很明显的看出来,输入样例1给出的第二排数列是step5,输出样例1的结果是step6.

所以,我的思路是对每一个元素进行插入排序,排序一次后就把sort()好的数据与输入时的第二行数列的每一个元素进行比较。每次排序时定义一个参数flag=0,表示一样的对数。如果一样,flag++; 如果flag==n,break;退出循环。最后 if(flag==n)说明时插入排序,否则为归并排序。

(有个1分的bug,测试点2,应该是插入排序哪里有点问题----猜测应该是启示或终止的某个地方有error)

(把“sort(v1,v1+i+1);”改成了“sort(v1,v1+i+2);”   测试点2没事儿了,但是测试点4又有毛病了。。。所以不要参考此代码,就当个思路看看倒是无妨~)

// 插入排序
for(i=1;i<=n;i++){
	flag=0;
	sort(v1,v1+i);
	for(int j=0;j<n;j++)
		if(v1[j]==v2[j]){
			flag++;
		}
	if(flag==n) break;
}
if(flag==n){
	cout<<"Insertion Sort"<<endl;
	sort(v1,v1+i+1);
	for(i=0;i<n;i++){
        if(i!=0) cout<<" ";
        cout<<v1[i]; 
    }	
}

但是根据插入排序的特性,可以发现,排序的前一部分是有序的序列,后一部分序列输入的两个数列是一样的。

后来看了柳神的解法,茅塞顿开:

for (int i = 0; i < n; i++)
    cin >> a[i];
for (int i = 0; i < n; i++)
    cin >> b[i];
for (i = 0; i < n - 1 && b[i] <= b[i + 1]; i++);
// 对输入的第二个数列遍历,查找它排好序的前半段

for (j = i + 1; a[j] == b[j] && j < n; j++);
// 将j指向从i+1开始,第一个不满⾜a[j] == b[j]的下标

if (j == n) {
    cout << "Insertion Sort" << endl;
    sort(a, a + i + 2);//注意 +2
} else {······}

柳神的方法在没有判断数列是插入排序还是归并排序之前不改动原数列,节省空间,真好!

如果数列为一次归并排序后的结果,不能直接使用输入的第二个数列,因为你要计算输入的第二个序列时经过了几次归并排序后得到的。

代码:(参考柳神)

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
    int n, a[100], b[100], i, j;
    cin >> n;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n; i++)
        cin >> b[i];
    for (i = 0; i < n - 1 && b[i] <= b[i + 1]; i++);
    for (j = i + 1; a[j] == b[j] && j < n; j++);
    if (j == n) {
        cout << "Insertion Sort" << endl;
        sort(a, a + i + 2);
    } else {
        cout << "Merge Sort" << endl;
        int k = 1, flag = 1;
        while(flag) {
        flag = 0;
        for (i = 0; i < n; i++) {
            if (a[i] != b[i])
            flag = 1;
        }
        k = k * 2;
        for (i = 0; i < n / k; i++)
            sort(a + i * k, a + (i + 1) * k);
        sort(a + n / k * k, a + n);
       }
    }
    for (j = 0; j < n; j++) {
        if (j != 0) printf(" ");
        printf("%d", a[j]);
    }
    return 0;
}

太难了这!!!这次考的5道题都好难

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值