1035 插入与归并(思路写注释代码里了,自己看)

根据维基百科的定义:

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

归并排序进行如下迭代操作:首先将原始序列看成 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

注意:

  1. 测试点5、6:归并排序中,若归并的每组数的数量为n,若最后一组数的数量不足n,此时最后一组数也要记得进行排序。如:

    7
    3 1 2 8 7 5 9
    1 3 2 8 5 7 4
#include<bits/stdc++.h>
using namespace std;
/*
我们平时再写归并时候用的是递归,先递归划分后排序左侧区间后再划分排序右侧区间
而本题的意思是传统意义上的归并排序,即平行,一块,一起进行划分排序,而不是先左后右,而是左右一起

例如:第一次排序为1个排序 第二次再进行两两合并后排序
(按照从小到大排序)
原始数列: 1 3 5 4 9 8 0
进行一次排序后: 1 |3 |5 |4 |9 |8 |0
第二次合并后排序: 1 3| 4 5| 8 9| 0
最后一个0虽然不够2个合并但仍然是有序的(因为上一次已经排成有序的了)
*/
int main(void) {
	int n;
	bool f = 1;
	cin >> n;
	int a1[n], a2[n];
	//输入
	for (int i = 0; i < n; ++i)
		cin >> a1[i];
	for (int i = 0; i < n; ++i)
		cin >> a2[i];


	/*
	判断类型
	一:i在类型为插入的时候存储的是有序序列中最后一个元素的下标
	输出再排序一次只需要把a 到 a+i+1元素排序即可
	二:i在类型为归并排序的时候存储的是第一个有序序列的最后一个元素的下标
	输出再排序一次时还需要找到下一个有序序列的最后一个元素的下标
	比较第一个有序序列和第二个有序序列的长度,以最小长度*2为下一次归并排序区间的长度

	为什么需要比较第一第二个有序序列长度找最短的长度?
	答案: 第2次的归并区间长度为2(这点没异议吧,不了解的先去补一下归并排序知识)
	例子:(按照从小到大排序)
	原始数列: 1 3 5 4 1 3 1 0
	(为什么是第二次呢?因为第一次是每个区间1个排列)
	第二次排序后: 1 3| 4 5| 1 3| 0 1
	会发现此时 i指向 为元素 5
	若只以第一个有序序列的长度为标准的话是4
	第一个有序序列:1 3 4 5
	而实际上区间划分长度为2
	第二个有序序列:1 3
	所以还要再找一个有序区间长度 以最小的为标准

	再举一个例子:
	原始数列: 1 3 5 4 0 1 3 2
	(为什么是第二次呢?因为第一次是每个区间1个排列)
	第二次排序后: 1 3| 4 5| 0 1|2 3
	第一个有序序列:1 3 4 5
	第二个有序序列:0 1 2 3
	最小长度为4  所以本次区间划分为4
	下次排序就4*2为8!!!!!!!
	*/
	int i = 0;
	for (i; i < n; ++i) {
		if (i != n - 1)
			if (a2[i] > a2[i + 1]) {
				for (int j = i + 1; j < n; ++j)
					if (a1[j] != a2[j]) {
						f = 0;
						break;
					}
				break;
			}
	}
	if (f) {
		//插入排序
		printf("Insertion Sort\n");
		if (i == n)
			sort(a2, a2 + i);
		else
			sort(a2, a2 + i + 2);
		bool r = 1;
		for (int o = 0; o < n; ++o) {
			printf("%s%d", r ? "" : " ", a2[o]);
			r = 0;
		}
	} else {
		//归并排序
		printf("Merge Sort\n");
		int j = i + 1;
		for (j; j < n ; ++j) {
			if (j != n - 1)
				if (a2[j] > a2[j + 1])
					break;
		}
		/*
		10
		3 1 2 8 7 5 9 4 0 6
		1 2 3 8 5 7 4 9 0 6
		*/
		//next_length为下一次归并区间排序长度
		int next_length = min(i + 1, j - i) * 2;
		for (int i = 0; i < n; i += next_length)
			if (i + next_length - 1 > n)
				sort(a2 + i, a2 + n);
			else
				sort(a2 + i, a2 + i + next_length);
		bool r = 1;
		for (int o = 0; o < n; ++o) {
			printf("%s%d", r ? "" : " ", a2[o]);
			r = 0;
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值