1035 插入與歸併 (25 point(s))
判斷是插入還是歸併函式。題目所說“保證每組測試的結果是唯一的”,所以判斷其中一個即可。而判斷插入函式,由於插入排序必然使得
所以插入排序滿足前面的元素有序,而後面的元素待排元素與原始序列相等。所以由以下程式碼來判斷。
a[j] == b[j]
if(j == n)
當後面待排元素和原始序列都滿足相等的條件,那麼就可以用 j == n 來判斷為插入排序。
sort(a, a + i + 2);
當時想了半天為什麼這裡要+2。對於插入排序來說,再迭代一輪就將已排序末尾的後一個未排序元素拉進來。而前面由
for (i = 0; i < n - 1 && b[i] <= b[i + 1]; i++);
給出了已排序元素的下標位置。但是下標 i 與後一個元素相差1。而 sort 是 sort (first, last) 對 [first, last) 範圍內的元素進行排序範圍內排序,不包括 last 所以要在下一個待排序元素的下標 i + 1 基礎上再 + 1。
以前都是 (a, a + n) 直接 + n 的,忽略了這樣用的真正原因是什麼。
同時這裡還學到,當有某些部分不理解的時候,需要將這部分裡面的細節拆開理解。比如前面的 sort 裡有一個 i,當時不理解這個 i 是幹什麼的。所以就用了 cout 將這個 i 及其它對應的元素打印出來。這才知道這個東西在這裡具有什麼意義。
int k = 1, flag = 1;
k 是每次歸併排序時,組的元素的個數,初始化為 1每一次進入迴圈時會對組的個數加倍。加倍後再進行歸併和排序。
k *= 2;
for(i = 0; i < n; i++)
if(a[i] != b[i])
flag = 1;
flag用來標記是否進行下一次迴圈,初始時設為1進入第一次迴圈,然後進入後初始化為 flag = 0,如果可以判斷為當前序列已經與中間序列 b[] 相等,那麼就不需要設 flag = 1,即不再進行下一次迴圈。本迴圈再排序迭代一次即結束。
for(i = 0; i < n / k; i++) sort(a + i * k, a + (i + 1) * k); sort(a + n / k * k, a + n);
這程式碼裡面出現兩次 n / k ,而因為 n 和 k 都是整數所以 n / k 的結果會向下取正。比如 n = 10,k = 3時,n / k = 3。
如果當最後一個組非 k 倍數時,比如上面的情況,那麼 for 迴圈會對前面整的組進行歸併和排序,而留下最後一個組單獨 sort 排序。
而單獨 sort 排序的話同樣有 n / k 並且還 * k,但同樣因為整型除法的向下取正,所以這裡的結果就是最後的組的首元素位置 n / k * k = 9。
當最後一個組為 k 倍數時,比如 n = 9, k = 3。那麼 for 迴圈剛好把三個組排序,而單獨的 sort 因為 n / k * k = 9, n = 9,所以只是對單一元素處理,不會導致其他的結果。
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, a[100], b[100], i, j;
cin >> n;
for(i = 0; i < n; i++)
cin >> a[i];
for(i = 0; i < n; i++)
cin >> b[i];
// 判斷是否是插入排序
for(i = 0; i < n && b[i] <= b[i+1]; i++);
for(j = i + 1; j < n && a[j] == b[j]; j++);
if(j == n){
cout << "Insertion Sort" << endl;
sort(a, a + i + 2);
}
else{
cout << "Merge Sort" << endl;
int k = 1, flag = 1;
while(flag){
flag = 0;
for(i = 0; i < n; i++)
if(a[i] != b[i])
flag = 1;
k *= 2;
for(i = 0; i < n / k; i++)
sort(a + i * k, a + (i + 1) * k);
sort(a + n / k * k, a + n);
}
}
for(i = 0; i < n; i++)
cout << (i ? " " : "") << a[i];
}