1. 程式人生 > >計算陣列中的逆序對

計算陣列中的逆序對

有一個由N個實數構成的陣列,如果一對元素A[i]和A[j]是倒序的,即i<j但是A[i]>A[j]則稱它們是一個倒置,設計一個計算該陣列中所有倒置數量的演算法。要求演算法複雜度為O(nlogn)

暴力求解

思路:
迴圈從陣列中取出一個元素k,然後從k之後的元素中找到比k小的元素個數,最後統計所有的個數即為排列中逆序對的數目。

時間複雜度: O(n^2)

修改歸併排序

前提知識:歸併排序
歸併排序是分治演算法一個重要的應用。
講解及程式碼:https://www.cnblogs.com/skywang12345/p/3602369.html#a42

思路:


根據歸併排序的基本思想,我們來到計算逆序對。
在歸併排序的合併操作時,陣列被劃分左右兩部分,此時假設左部分的逆序對有a個 ,右邊有b個,如果左邊存在一個數a[i]大於右邊的數a[j],由於兩陣列分別是有序的,那麼從a[i]到左邊結束部分的數字都比a[j]大,即與b[j]有關的逆序對數=(左邊部分的end)-i+1 個。
那麼我們只需要在每次合併操作時統計這部分個數並求和,僅在merge函式內加一條語句。
(ps:左右兩部分內部的分別排序不會影響兩部分之間的逆序對數,因為只是內部有序。)

程式碼

#include <iostream>
using namespace std;
void merge(int a[],int start,int mid,int end,int &num){ int *tmp=new int[end-start+1]; int s=start; int m=mid+1; int e=end; int k=0; while(s<=mid && m<=e){ if(a[s]>a[m]){ tmp[k++]=a[m++]; num+=mid-s+1; //逆序數增加 end- i + 1個
} else{ tmp[k++]=a[s++]; } } while(s<=mid) tmp[k++]=a[s++]; while(m<=e) tmp[k++]=a[m++]; for (int i = 0; i < k; i++) a[start + i] = tmp[i]; } void mergeSort(int a[],int start,int end,int &num){ if(start==end) return; int mid=(start+end)/2; mergeSort(a,start,mid,num); mergeSort(a,mid+1,end,num); merge(a,start,mid,end,num); } int main(){ int a[]={8,3,2,9,7,1,5,4}; int num=0; //儲存逆序陣列對數 mergeSort(a,0,7,num); //7是陣列a的長度 cout<<num<<endl; return 0; }

時間複雜度:O(nlog n)