分治法 歸併排序 加上逆序數求法

2021-07-15 04:39:21 字數 1889 閱讀 6396

分治法:

字面意義就是分而治之,把大的問題分成小的相似的子問題,遞迴的解決掉小問題,最終合起來解決大問題

分治法在每層遞迴時都有三個步驟:

分解原問題為若干子問題,這些子問題都是原問題的規模較小的例項;

解決這些子問題(遞迴)

合併這些子問題的解

分治法的乙個應用就是歸併排序,是一種穩定的快速的排序,(θ(n*logn))

分解: 待排序的n為 n/2 n/2兩組

解決: 歸併排序遞迴的解決兩組

合併: 合併兩個已經有序的子串行

關鍵步驟為合併步(merge),需要θ(n)時間

偽**如下:

merge(a,p,q,r)

n1 = q-p+1;

n2 = r-q;

new arrays l[n1 + 2], r[n2+2];

for(i= 1; i<=n1;i++ )

l[i] = a[p+i-1];

for(j = 1;j <=n2;j++)

r[j] = a[q+j];

l[n1+1] = 無窮大;

r[n2+1] = 無窮大;//哨兵牌 避免每次檢查是否有空

i = 1; j= 1;

for(k = p; k<=r;k++)

if(l[i] < r[j])

a[k] = l[i];i++;

else

a[k] = r[j];j++;

mergesort(a,p,r)

:if(p2;

mergesort(a,p,q);

mergesort(a,q+1,r);

merge(a,p,q,r);

}

c++**如下:

#include

#include

using

namespace

std;

const

int mm = (1

<<30);

int count = 0;//用來求逆序數

void mergee(int a, int p, int q, int r)

else

}}

void merge_sort(int a, int p, int r)

}

int main()

{ int n;

while(cin>>n)

{int num[n+2];

for(int i = 1; i<=n; i++)

cin>>num[i];

merge_sort(num,1,n);

for(int i = 1; i<=n; i++)

cout

<" ";

cout

<< count《歸併排序演算法分析:

分解:計算中間位置 θ(1);

解決: 2* t(n/2);

合併:θ(n);

t(n) = θ(1)(n == 1)

t(n) = θ(n) + 2*t(n/2) (n>1);

關於逆序數的補充

如果排在前面的數比排在後面的數大,那就構成了一對逆序,比如

1 6 8 2 7

逆序有 6-2 8-2 8-7

用分治法的思想呢, 當兩組數分別是(1,6,8) (2,7)時,進行歸併排序時

先拿出左邊的1, 再拿出右邊的2放進來時,實際要放在6的前面,因為2比較小,因此對2來講,就有逆序6和8兩個,也即是左邊組的長度從減掉前面的 用上面的**表示就是 n1-i+1注意是n1而不是中間的q,而再選左邊的6時,不會有位置的變化,不會產生逆序

分治法求解逆序數 歸併排序

題目內容 設a1,a2,an是集合的乙個排列,如果iaj,則序偶 ai,aj 稱為該排列的乙個逆序。例如,2,3,1有兩個逆序 3,1 和 2,1 設計演算法統計給定排列中含有逆序的個數。輸入格式 第一行輸入集合中元素個數n,第二行輸入n個集合元素 輸出格式 含有逆序的個數 輸入樣例 32 3 1 ...

分治遞迴逆序數 模板 歸併排序 逆序數 分治

歸併排序 圖來自維基 遞迴呼叫的過程需要在腦中模擬清楚 然後是 的細節問題 多複習多理解 劉汝佳版 include using namespace std const int maxn 1e5 10 int ans 0 int arr maxn int brr maxn void mergesort...

歸併排序 逆序數

對於數列a,將其二分地拆分為b,c 先將b,c分別排序好,再合併b,c即為總的排序,不過在合併的過程中我們可以算出逆序數哦。其原理網上很多,我這裡不再贅述,只給出實現 include include define ll long long using namespace std ll mergeso...