1. 程式人生 > >歸併排序求逆序數(排序演算法)

歸併排序求逆序數(排序演算法)

歸併排序:歸併排序是建立在歸併操作上的一種有效的排序演算法,該演算法是採用分治法(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;
}