PAT Insert or Merge
给你一段初始序列,以及已经排序了一部分的序列,需要判断是采取的插入排序还是归并排序,并输出下一次迭代后的序列。
如果是考试的话,我肯定会直接模拟,把整个排序的过程写出来,然后每次排序一部分后对比,看看是否和题目所给的序列符合。当然我一次就直接这么写的,然后基本上什么都不用考虑就过了。因为数据范围很小,所以也不会超时。但是这道题的目的肯定不是让你这么写。
思路
不考虑直接模拟该怎么写呢,首先我们分析归并排序和插入排序的区别,我们知道,插入排序是从头开始的,也就是说,一个已经被部分排序的序列,前面的序列一定是有序的,后面的序列则一定同原始的序列元素一致,我们需要根据这一点,找到有序部分的最后一个元素 i i i, 然后从 i i i开始判断后面的元素是否同原始序列一致,若一致,说明采用的方法是插入排序,那么返回 i i i,从 i i i开始在往后排序一个元素。否则返回-1,说明是归并排序。
如果是归并排序,那么则是分段有序的,即对于一个长度为
2
l
2l
2l的序列,其内部一定是有序的,我们只需要枚举
l
l
l,判断最长的归并段长度,如果在长度为
2
l
2l
2l时不满足有序,说明归并恰好执行到归并长度为
2
l
2l
2l之前,那我们直接再对这个长度进行一次归并并输出就好了。
#include <iostream>
using namespace std;
int N;
int A[110], B[110], Tmp[110];
int judge_Insert() {
int i;
for (i = 1; i < N; i++) {
if(B[i] < B[i-1]) break;
}
for (int j = i; j < N; j++) {
if (B[j] != A[j]) return -1;
}
return i;
}
void Insertion_Sort(int P) {
int dat = B[P], j;
for (j = P; j > 0 && B[j-1] > dat; j--) {
B[j] = B[j-1];
}
B[j] = dat;
for (int i = 0; i < N; i++) {
cout << B[i];
if (i != N-1) cout << " ";
}
}
bool check(int s, int e) {
for (int i = s + 1; i <= e; i++) {
if (B[i] < B[i-1]) return false;
}
return true;
}
void merge(int s, int m, int e) {
int pb = 0;
int p1 = s, p2 = m + 1;
while (p1 <= m && p2 <= e) {
if (B[p1] < B[p2]) Tmp[pb++] = B[p1++];
else Tmp[pb++] = B[p2++];
}
while (p1 <= m) Tmp[pb++] = B[p1++];
while (p2 <= e) Tmp[pb++] = B[p2++];
for (int i = 0; i < e-s+1; i++)
B[s+i] = Tmp[i];
}
void Merge_from_L(int len) {
for (int i = 0; i+len-1 < N; i += 2*len)
merge(i, i+len-1, min(N-1, i+2*len-1));
for (int i = 0; i < N; i++) {
cout << B[i];
if (i != N-1) cout << " ";
}
}
void Merge_Sort() {
bool f = 0;
int l = 1;
for (l = 1; l < N; l *= 2) {
for (int i = 0; i < N; i += 2*l) {
if(!check(i, min(i+2*l-1, N-1))) {
f = 1; break;
}
}
if (f == 1) break;
}
Merge_from_L(l);
}
void solve() {
int f;
f = judge_Insert();
if (f != -1) {
cout << "Insertion Sort" << endl;
Insertion_Sort(f);
} else {
cout << "Merge Sort" << endl;
Merge_Sort();
}
}
int main() {
cin >> N;
for (int i = 0; i < N; i++) cin >> A[i];
for (int i = 0; i < N; i++) cin >> B[i];
solve();
return 0;
}
其实看似比直接模拟精巧,思维也更多,但是单单110的数据范围,对于两者来说效率并没有多大差距,如果是考试的时候,为了拿分,肯定优先选择最好写的那个,不要挑战自我在翻车。自己设计一些算法是很容易在一些边界数据WA的毕竟。