標籤:style color os 問題 代碼 for
(一)歸併排序
分析:
(1)劃分問題:把序列分成元素個數盡量相等的兩半。
(2)遞迴求解:把兩半元素分別排序。
(3)合并問題:把兩個有序表合并成一個。(每次只需要把兩個序列的最小元素加以比較,刪除其中的較小元素並加入合并後的新表)
#include <iostream>using namespace std;const int MAXN = 1000;int A[MAXN], T[MAXN];void merge_sort(int *A, int x, int y, int *T) {if(y - x > 1) {int m = x + (y - x) / 2; //劃分int p = x, q = m, i = x;merge_sort(A, x, m, T); //遞迴求解merge_sort(A, m, y, T); //遞迴求解while(p < m || q < y) {if(q >= y || (p < m && A[p] <= A[q])) T[i++] = A[p++]; //從左半數組複製到臨時空間else T[i++] = A[q++]; //從右半數組複製到臨時空間}for(i = x; i < y; ++i) A[i] = T[i]; //從輔助空間複製回A數組}}int main() {int n;cin >> n;for(int i = 0; i < n; ++i) cin >> A[i];merge_sort(A, 0, n, T);for(int i = 0; i < n; ++i) cout << A[i] << endl;return 0;}上述代碼中的兩個條件是關鍵!
首先,只要有一個序列非空,就要繼續合并while(p < m || q < y)。
其次對於:if(q >= y || (p < m && A[p] <= A[q]))。
(1)如果第二個序列為空白,這個時候第一個序列肯定非空,不然就不能進入while迴圈,這個時候覆制A[p]。
(2)否則(第二個序列非空),若且唯若第一個序列也非空,且A[p] <= A[q]時,才複製A[p]。
(二)利用歸併排序思想求解逆序對數
題目:給一列數,求它的逆序對數!
分析,由於n可能很大,所以O(n2)的枚舉方法肯定逾時。所以要用分治的方法!
(1)劃分問題:把序列分成元素個數盡量相等的兩半。
(2)遞迴求解:統計i和j均在左邊或者均在右邊的逆序對個數。
(3)合并問題:統計i在左邊,j在右邊的逆序對個數。
劃分以後,對於右邊的每個j,統計左邊比它大的元素個數f(j),則所有f(j)之和便是答案。
所以由於我們的歸併排序操作是從小到大進行的,當右邊的A[j]複製到T中時,左邊還沒有來得及複製到T的那些數就是左邊所有比A[j]大的數。
所以此時在累加器中加上左邊元素個數m-p就可以了!
#include <iostream>using namespace std;const int MAXN = 1000;int A[MAXN], T[MAXN];void inverse_pair(int *A, int x, int y, int* cnt, int *T) {if(y - x > 1) {int m = x + (y - x) / 2; //劃分int p = x, q = m, i = x;inverse_pair(A, x, m, cnt, T); //遞迴求解inverse_pair(A, m, y, cnt, T); //遞迴求解while(p < m || q < y) {if(q >= y || (p < m && A[p] <= A[q])) T[i++] = A[p++]; //從左半數組複製到臨時空間else {T[i++] = A[q++]; //從右半數組複製到臨時空間*cnt += m-p; //更新累加器}}for(i = x; i < y; ++i) A[i] = T[i]; //從輔助空間複製回A數組}}int main() {int n;cin >> n;for(int i = 0; i < n; ++i) cin >> A[i];int cnt = 0;inverse_pair(A, 0, n, &cnt, T);cout << cnt << endl;return 0;}