分治法:
字面意義就是分而治之,把大的問題分成小的相似的子問題,遞迴的解決掉小問題,最終合起來解決大問題
分治法在每層遞迴時都有三個步驟:
分解原問題為若干子問題,這些子問題都是原問題的規模較小的例項;
解決這些子問題(遞迴)
合併這些子問題的解
分治法的乙個應用就是歸併排序,是一種穩定的快速的排序,(θ(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...