逆序對(歸併排序)

Description

在這個問題中,你需要分析一個對n個不同數排序的算法。該算法主要通過交換相鄰數直到序列有序(升序)。比如:對輸入序列

                  9 1 0 5 4

經過一系列交換後變成有序序列

                  0 1 4 5 9

你的任務是計算將序列變成有序最少需要經過多少次交換。

Input

輸入包含多組測試數據。每組第一個是整數n<500,000,表示輸入序列的長度,接下來是n行,每行有一個整數ai。當n=0時表示結束。

Output

對每一組輸入,輸出該序列變成有序所需要交換的最少的次數。

Sample Input

5
9
1
0
5
4
3
1
2
3
0
Sample Output

6
0
解題思路:看到這個題按照題目意思“要通過交換相鄰數直到序列有序(升序)”這是什麼?冒泡排序?雖然冒泡排序就是基於這種思想,可是O(n^2)的時間
複雜度並不允許我這麼搞,那該怎麼辦?
模擬原始做法:
對於數組:4 8 2 7 5 6 1 3
1 4 8 2 7 5 6 3------>6次
1 2 4 8 7 5 6 3------>2次
1 2 3 4 8 7 5 6------>5次
1 2 3 4 5 8 7 6------>2次
1 2 3 4 5 6 8 7------>2次
1 2 3 4 5 6 7 8------>1次

在模擬過程中,我們發現每次都是找到一個最小的然後移到最前面,但是除了這個最小的,其他數的相對次序並沒有改變,所以我們可以將原始做法換一種表述方式:

找到最小的,統計它前面有多少個數比它大,然後加入結果,將這個最小的刪去。如此反覆。
1.歸併排序是利用歸併的思想實現的排序方法,在這裏插入圖片描述該算法採用經典的分治策略

2.歸併排序是穩定排序

3.歸併排序的最好,最壞,平均時間複雜度均爲O(nlogn)。

例子:
在這裏插入圖片描述

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
#define maxn 500010
LL a[maxn];
LL temp[maxn];
LL sum;
void Merge(int l,int r,int m)
{
    int i=l;
    int j=m+1;
    int k=l;
    while(i<=m&&j<=r)
    {
        if(a[i]>a[j])
        {
            sum+=m-i+1;
            temp[k++]=a[j++];
        }
        else
        {
            temp[k++]=a[i++];
        }
    }

    while(i<=m)
    {
        temp[k++]=a[i++];
    }
    while(j<=r)
    {
        temp[k++]=a[j++];
    }
    for(i=l; i<=r; i++)
    {
        a[i]=temp[i];
    }
}
void mergesort(int l,int r)
{
    if(l<r)
    {
        int mid=(l+r)/2;
        mergesort(l,mid);
        mergesort(mid+1,r);
        Merge(l,r,mid);
    }
}
int main()
{
    int n,i;
    while(~scanf("%d",&n))
    {
        if(n==0)
            break;
        for(i=0; i<n; i++)
        {
            cin>>a[i];
        }
        sum=0;
        mergesort(0,n-1);
        cout<<sum<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章