今天寫乙個歸併排序的模板,返回值為該序列的逆序對數
基本思路
歸併排序就是利用二分的思想,將區間無限遞迴二分,直到當前劃分區間只包含乙個元素或沒有元素的時候(我們認為這個序列是自動有序的),我們回溯到上一層,然後將當前層的左右兩個區間合併為乙個有序序列,然後繼續回溯,回溯之後,當前層的左右兩個區間都應該分別是已經經過合併的有序子區間,我們將這兩個有序子區間再進行有序合併,再返回上一層,直到返回最大區間,則合併最大區間的左右有序子區間,得到有序序列。
流程演示
比如:22 3 1 5 4
7 9 1 8 0
紅色區間劃分:22 3
1 5 4
左邊:22
3 右邊
15 4
左邊:合併有序:3 22
右邊:5 4區間遞迴返回時候變為:4 5
右邊合併:1 4 5
左右區間合併為乙個區間:1 3 4 5 22
至此左側區間處理完畢
右側區間同理,得到有序序列:0 1 7 8 9
最後合併整個區間
0 1 1 3 4 5 7 8 9 22
逆序對數
我們利用歸併的思想,它會將每個區間細分到最小,返回整合的時候,會進行左右區間合併,合併的時候就要比較左右區間當前值那個大,然後取小的那個,我們可以在比較的時候做記錄,如果左側的值小於右側,我們就做記錄,這樣一路回溯,就會找到所有的逆序對數。
我們利用歸併排序的返回值來將此記錄值輸出到外部
泛型**:
templateint merge_sort(const value_ptr& begin, const value_ptr&end)測試與使用; //
記錄逆序對數
if (end - begin <= 1)return0;
value_ptr mid = begin + (end - begin) / 2
; merge_sort
(begin, mid);
merge_sort
(mid, end);
//將上述兩段區間順序排列
value_ptr l = begin, r =mid;
int k, index;
while (l < mid && r
if (*l < *r)to[k++] = *l++;
else
//如果左側值小於右側
while (l < mid)to[k++] = *l++;
while (r < end)to[k++] = *r++;
for (index = 0; begin + index < end; ++index)*(begin + index) =to[index];
return
cnt;
}
#include #includeusing
namespace
std;
intmain()
; vector
v;int cnt = merge_sort(list + 0, list + 10
); merge_sort
(v.begin(), v.end());
for (auto it : v)cout << it << "";
cout
<
for (auto it : list)cout << it << "";
cout
<
cout
<< "
逆序對數:
"<< cnt << endl <
char list_[10];
vector
v_;cnt = merge_sort(list_ + 0, list_ + 10
); merge_sort
(v_.begin(), v_.end());
for (auto it : v_)cout << it << "";
cout
<
for (auto it : list_)cout << it << "";
cout
<
cout
<< "
逆序對數:
時間複雜度為:o(n * log n)
歸併排序及逆序對演算法
排序都用qsort了,別的排序演算法不怎麼用,但有些排序的思想很重要。碰到一道求逆序對的題,要用到歸併排序,學習了一下歸併排序。歸併排序是用分治思想,分治模式在每一層遞迴上有三個步驟 分解 將n個元素分成個含n 2個元素的子串行。解決 用合併排序法對兩個子串行遞迴的排序。合併 合併兩個已排序的子串行...
歸併排序 及拓展 逆序對
時間複雜度 歸併排序時間複雜度為o nlogn 似乎和快速排序差不多,但在有些特定的場合下,歸併排序卻能起到快速排序達不到的效果 如一年的聯賽題,瑞士輪 思路及實現 歸併排序分為兩個步驟,分 合 分 的過程我們用二分的思路實現 合 的過程時間複雜度可達到o n 分 進行分治 假設當前處理的區間為l ...
逆序對 (歸併排序)
逆序對的nlogn方法,改進後的歸併排序 給定排列p,求排列的逆序對數量。p的長度 100000。要求o nlogn 定義歸併排序過程merge l,r merge l,r merge l,mid merge mid 1,r count l,mid,mid 1,r 只需要考慮左右兩段之間造成的逆序對...