計算陣列中的逆序對
阿新 • • 發佈:2019-01-06
有一個由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)