進階指南--超快速排序(歸併+逆序對)
歸併排序:
將陣列切成兩半,然後左邊排完 右邊排完 (二分遞迴) 合併排列(用臨時陣列:對左右兩邊的數誰大誰進去)
逆序對
對於i,j (i < j ) 如果 a[i] < a[j] 則構成一個逆序對
那思考:歸併排序 你知道左邊一個單調遞增數列,右邊一個單調遞增數列,mid是左右分界,屬於左邊,那對於右邊的數 a[j] 而言,在合併的時候,如果發現自己小於前面的一個數 a[i] 進了陣列, 那說明 a[i]~a[mid] 都比a[j] 大,構成了(mid-i+1) 個逆序對
這樣子,在合併的時候記錄逆序對,通過歸併排序就記錄了逆序對的個數
超快速排序
相鄰交換,你會發現如果交換一次 a[i],a[i+1],(a[i] > a[i+1])就等價於減少一個逆序對,因為要最小次數,那你每次選相鄰兩個 a[i] > a[i+1] 即為最優,那麼這樣子做的結果就是把逆序對變為0,結果數即為逆序對的總個數
#include <bits/stdc++.h>
using namespace std;
const int MA = 5e5+10;
int a[MA],b[MA];
long long cnt;//小心溢位!!
void merge (int l,int r){
if(l >= r) return ;
//切成兩半
int mid = (l+r)>>1;
merge(l,mid);
merge(mid+1,r);
//開始合併兩個有序佇列
int i = l,j = mid+1;
for (int k = l; k <= r; k++){
//邊界和正常情況
if(j > r || (i <= mid && a[i]<a[j] ) ) b[k] = a[i++];//左小於右仍有序
else b[k] = a[j++], cnt += mid - i + 1;
}
for (int k = l; k <= r; k++) a[k] = b[k];
return;
}
int main()
{
int n;
while(scanf("%d",&n)==1 && n){
for (int i = 0; i < n; i++) scanf("%d",&a[i]);
cnt = 0;
merge(0,n-1);
cout<<cnt<<endl;
}
return 0;
}
相關文章
- HDU 2689 【歸併排序求逆序對】排序
- 歸併排序的經典-求逆序對排序
- 逆序對的數量(歸併排序模板)排序
- 快速排序&&歸併排序排序
- 四、歸併排序 && 快速排序排序
- php實現 歸併排序,快速排序PHP排序
- php插入排序,快速排序,歸併排序,堆排序PHP排序
- 氣泡排序、歸併排序與快速排序比較排序
- 歸併排序排序
- 直播系統原始碼,實現快速排序和歸併排序原始碼排序
- 歸併排序與快速排序的一個實現與理解排序
- C++快速排序與歸併排序的實現(LeetCode 912)C++排序LeetCode
- 七、排序,選擇、冒泡、希爾、歸併、快速排序實現排序
- java歸併排序Java排序
- 排序演算法之歸併,快速,堆和桶排序演算法
- 演算法之常見排序演算法-氣泡排序、歸併排序、快速排序演算法排序
- 歸併排序--排序演算法排序演算法
- 排序演算法(歸併排序)排序演算法
- 歸併排序--二路排序排序
- 歸併排序和基數排序排序
- 排序演算法__歸併排序排序演算法
- 排序演算法:歸併排序排序演算法
- 排序演算法 - 歸併排序排序演算法
- Python進階-演算法-快速排序Python演算法排序
- LeetCode C++ 劍指 Offer 51. 陣列中的逆序對【歸併排序/樹狀陣列/線段樹】LeetCodeC++陣列排序
- 歸併排序 js demo排序JS
- 【資料結構與演算法】高階排序(希爾排序、歸併排序、快速排序)完整思路,並用程式碼封裝排序函式資料結構演算法排序封裝函式
- 排序演算法之 '歸併排序'排序演算法
- 歸併排序 nO(lgn) 稽核中排序
- 歸併排序——C語言排序C語言
- go 實現歸併排序Go排序
- 歸併排序加例題排序
- 演算法與資料結構高階排序演算法之歸併排序演算法資料結構排序
- 洛谷題單指南-分治與倍增-P1177 【模板】歸併排序排序
- 歸併排序的簡單理解排序
- 歸併排序 2020-09-20排序
- 演算法之歸併排序演算法排序
- 使用 Swift 實現歸併排序Swift排序