1. 程式人生 > 其它 >1089. Insert or Merge (25) - PAT甲級真題

1089. Insert or Merge (25) - PAT甲級真題

技術標籤: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(); } }