1. 程式人生 > >【歸併排序】【求逆序對】

【歸併排序】【求逆序對】

歸併排序:
假設,每次排一段序列時就已經分別擁有了兩段已經拍好順序的子列,合併時每次只比較兩子列的首項,並取出較小(大)的一項補在正在構建的新的目標序列尾部,重複這項操作,直至這一段序列排好順序。
照此方法遞迴進行。
遞迴的每一層,每個數都會參與一次比較,一層內複雜度為 O(n)。
每次分為兩段,複雜度 log2(n)。
總複雜度n*log2(n)。

int a[100005],b[100005];
void guibing(int l,int r)
{
    if (l>=r) return ;
    int mid=(l+r)/2;
    guibing(l,mid);
    guibing(mid+1
,r); for (int i=l,j=l,k=mid+1;i<=r;i++)//構建新數列 { if (a[j]<=a[k] && j<=mid) b[i]=a[j],j++; else if (k<=r) b[i]=a[k],k++; else b[i]=a[j],j++; } for (int i=l;i<=r;i++) a[i]=b[i]; return ; }

以及在歸併排序中可以很輕鬆的實現求逆序對數量的操作。

#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int n,ans,a[100005],b[100005];
void guibing(int l,int r)
{
    if (l>=r) return ;
    int mid=(l+r)/2;
    guibing(l,mid);
    guibing(mid+1,r);
    for (int i=l,j=l,k=mid+1;i<=r;i++)
    {
        if (a[j]<=a[k] && j<=mid)
        b[i]=a[j],j++;
        else
if (k<=r) b[i]=a[k],k++,ans+=mid-j+1; else b[i]=a[j],j++; } for (int i=l;i<=r;i++) a[i]=b[i]; return ; } int main() { scanf("%d",&n); ans=0; for (int i=1;i<=n;i++) scanf("%d",&a[i]); guibing(1,n); printf("%d\n",ans); }