歸併排序求逆序數(排序演算法)
阿新 • • 發佈:2019-02-16
歸併排序:歸併排序是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(Divide and Conquer)的一個非常典型的應用。將已有序的子序列合併,得到完全有序的序列;即先使每個子序列有序,再使子序列段間有序。若將兩個有序表合併成一個有序表,稱為二路歸併。——(摘自百度百科)
具體操作:
比較a[i]和a[j]的大小,若a[i]≤a[j],則將第一個有序表中的元素a[i]複製到r[k]中,並令i和k分別加上1;否則將第二個有序表中的元素a[j]複製到r[k]中,並令j和k分別加上1,如此迴圈下去,直到其中一個有序表取完,然後再將另一個有序表中剩餘的元素複製到r中從下標k到下標t的單元。歸併排序的演算法我們通常用遞迴實現,先把待排序區間[s,t]以中點二分,接著把左邊子區間排序,再把右邊子區間排序,最後把左區間和右區間用一次歸併操作合併成有序的區間[s,t]。
在這裡先講一下 如果有兩個陣列是有序的話,那麼我們怎麼進行排序呢,肯定是兩個指標i,j每次後移,判斷的時候就是這樣:
#include <iostream>
#include <cstdio>
using namespace std;
int a[15],b[15],c[15];
void Merge_Sort(int n, int m)///n是陣列a的長度,m是陣列b的長度
{
int i, j, k;
i = j = k = 0;
while(i<n && j<m)
{
if(a[i] < b[j])///因為是已經排好序的只要a[i]比b[j]小i就後移
c[k++] = a[i++];
else ///同理
c[k++] = b[j++];
}
while(i < n)///這個是b陣列已經全部比完
c[k++] = a[i++];
while(j < m)///這個是a陣列已經全部比完
c[k++] = b[j++];
}
int main()
{
int n, m;
while(cin>>n>>m)
{
for(int i=0; i<n; i++)
cin>>a[i];
for(int i=0 ; i<m; i++)
cin>>b[i];
Merge_Sort(n, m);
for(int i=0; i<n+m; i++)
cout<<c[i]<<" ";
}
return 0;
}
其實歸併排序就是跟上面一樣的,只不過呢,我們要做的是將兩個兩個陣列進行排序,給一組樣例:
6 2 7 5 3 1 4
第一步:(6,2) (7,5) (3,1) (4)
兩兩排序(2,6)(5,7)(1,3)(4)
第二步:{(2,6),(5,7)}{(1,3),(4)}
兩兩排序(2,5,6,7) (1,3,4)
第三步:{(2,5,6,7),(1,3,4)}
兩兩排序 1 2 3 4 5 6 7
其實我們就是先用遞迴演算法將這 n 個數分解成一個一個的數,因為這樣是已經排好序的,然後我們在兩兩進行合併,接下來給一個歸併排序求逆序數的程式碼:
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 50000+5;
int cnt = 0;
int a[MAXN],p[MAXN];
void Merge_Array(int first, int mid, int last)
{
int i=first, j=mid+1, k=first;
while(i<=mid && j<=last)
{
if(a[i] <= a[j])
p[k++] = a[i++];
else
{
p[k++] = a[j++];
cnt += j-k;
}
}
while(i <= mid)
p[k++] = a[i++];
while(j <= last)
p[k++] = a[j++];
for(int i=first; i<=last; i++)
a[i] = p[i];
}
void Merge_Sort(int first, int last)
{
if(first < last)
{
int mid = (first + last) >> 1;
Merge_Sort(first, mid);
Merge_Sort(mid+1, last);
Merge_Array(first, mid, last);
}
}
int Scan()///輸入外掛
{
int res=0,ch,flag=0;
if((ch=getchar())=='-')
flag=1;
else if(ch>='0'&&ch<='9')
res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return flag?-res:res;
}
void Out(int a)///輸出外掛
{
if(a>9)
Out(a/10);
putchar(a%10+'0');
}
int main()
{
int n;
while(~scanf("%d",&n))
{
cnt = 0;
for(int i=0; i<n; i++)
a[i] = Scan();
Merge_Sort(0, n-1);
Out(cnt);
puts("");
}
return 0;
}