1035. 插入与归并(25)

题目描述

根据维基百科的定义:

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

归并排序进行如下迭代操作:首先将原始序列看成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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <cstdio>
#include <algorithm>
using namespace std;

int main()
{
int n, i, j;
int raw_seq[100];
int mid_seq[100];

scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &raw_seq[i]);
}
for (i = 0; i < n; i++) {
scanf("%d", &mid_seq[i]);
}

for (i = 1; i < n; i++) {
if (mid_seq[i] < mid_seq[i - 1]) {
break;
}
}
// i 指向无序区第一个元素
for (j = i; j < n; j++) {
if (mid_seq[j] != raw_seq[j]) {
break;
}
}
if (j == n) {
printf("Insertion Sort\n");
for (j = i; j > 0; j--) {
if (mid_seq[j] < mid_seq[j - 1]) {
swap(mid_seq[j], mid_seq[j - 1]);
}
}
printf("%d", mid_seq[0]);
for (i = 1; i < n; i++) {
printf(" %d", mid_seq[i]);
}
printf("\n");
} else {
printf("Merge Sort\n");
j = 2;
bool flag;
do {
flag = true;
for (i = 0; i < n; i++) {
if (raw_seq[i] != mid_seq[i]) {
flag = false;
}
}
for (i = 0; i + j < n; i = i + j) {
sort(raw_seq + i, raw_seq + i + j);
}
sort(raw_seq + i, raw_seq + n);
j *= 2;
// for (i = 0; i < n; i++) {
// printf("%d ", raw_seq[i]);
// }
// printf("\n");
} while (!flag);
printf("%d", raw_seq[0]);
for (i = 1; i < n; i++) {
printf(" %d", raw_seq[i]);
}
printf("\n");
}

return 0;
}

个人思考

最初的思路就是直接对原数组进行排序,然后对照中间结果确认是哪种排序方式。然而插入排序有其明显特点,分有序区和无序区,假如无序区和原数组一模一样,那就是插入排序无疑了。对于归并排序,则在判断后直接按一开始的思路来进行即可。印象中的归并排序只有递归版本,不好判断中间结果,于是查看了维基百科上归并排序的词条,重写了非递归的版本。

注意sort 函数中的起始地址和结束地址,是一个左闭右开的区间,也就是说,结束地址并不是真实指向要排序队列中最后一个元素的地址。之前一直用的 sort(vec.begin(), vec.end()) 是为知其然而不知其所以然。知道这次用了 sort 对数组进行排序,最后一个元素没有被考虑进来才发现这个盲区。

一开始提交的时候忘了把注释部分的代码删掉,错了好几个 =_=

参考资料