進階指南--超快速排序(歸併+逆序對)
歸併排序:
將陣列切成兩半,然後左邊排完 右邊排完 (二分遞迴) 合併排列(用臨時陣列:對左右兩邊的數誰大誰進去)
逆序對
對於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 【歸併排序求逆序對】排序
- 逆序對的數量(歸併排序模板)排序
- 歸併排序的經典-求逆序對排序
- 歸併排序-陣列中的逆序對排序陣列
- 歸併排序求逆序數排序
- 快速排序&&歸併排序排序
- 用“歸併”改進“快速排序” (轉)排序
- 歸併排序思想應用之----求陣列中的逆序對排序陣列
- 四、歸併排序 && 快速排序排序
- HDU 4911 Inversion(歸併排序求逆序數)排序
- php實現 歸併排序,快速排序PHP排序
- 歸併排序與快速排序的簡明實現及對比排序
- php插入排序,快速排序,歸併排序,堆排序PHP排序
- 氣泡排序、歸併排序與快速排序比較排序
- 歸併和快速排序思想的延伸排序
- O(lgn)的三種排序,快速排序、歸併排序、堆排序排序
- 藍橋杯 小朋友排隊 (歸併排序 逆序數 好題)排序
- [排序] 歸併排序排序
- 七、排序,選擇、冒泡、希爾、歸併、快速排序實現排序
- 【分治演算法】歸併排序,快速排序和漢諾塔演算法排序
- 歸併排序排序
- 直播系統原始碼,實現快速排序和歸併排序原始碼排序
- 歸併排序與快速排序的一個實現與理解排序
- java歸併排序Java排序
- [java]歸併排序Java排序
- 歸併排序模板排序
- 排序演算法之歸併,快速,堆和桶排序演算法
- 演算法之常見排序演算法-氣泡排序、歸併排序、快速排序演算法排序
- 演算法系列(四)排序演算法中篇--歸併排序和快速排序演算法排序
- 排序演算法Python(冒泡、選擇、快速、插入、希爾、歸併排序)排序演算法Python
- 歸併排序--二路排序排序
- 排序演算法__歸併排序排序演算法
- 排序演算法:歸併排序排序演算法
- 歸併排序和基數排序排序
- 歸併排序--排序演算法排序演算法
- 排序演算法 - 歸併排序排序演算法
- 排序演算法——歸併排序排序演算法
- 排序演算法(歸併排序)排序演算法