1089. Insert or Merge (25) - PAT甲級真題
阿新 • • 發佈:2021-02-04
技術標籤:PTA
該題是預設遞增排序的,以下不再贅述。
- 如何判斷是歸併排序還是插入排序呢
樣例
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();
}
}