利用歸併排序求逆序對

2021-07-05 02:15:34 字數 1480 閱讀 4955

在逆序對的問題中,如果採用暴力求解的方法,一般也是有效的,但是o(n2)時間複雜度實在是難以接受的。但是對於逆序對問題,卻有乙個看似不想關的演算法來解決–歸併排序。時間複雜度和空間複雜度完全與歸併排序一樣,只是在歸併過程中,新增了乙個變數,對於逆序對的數目進行了記錄。這樣就將時間複雜度降低到了o(nlogn)。

因為逆序對的數目可能存在平方數個逆序對,因此要想將逆序對數目求解的複雜度降低到o(nlogn),就不能對每乙個逆序對進行計算。根據歸併排序思想,使用歸併求解逆序對時,將會在將兩個有序陣列合併成乙個有序陣列的過程中,記錄逆序對的數目,其他如陣列劃分和排序過程同歸並排序。

在歸併排序的合併步驟中,假設將兩個有序陣列a 和有序陣列b 和並為乙個有序陣列c。計算逆序對問題轉換為計算逆序對(a,b)的問題,其中a來自a, b來自b。當a < b的時候,不計數,當a>b的時候(a,b)就是逆序對,由於a是有序的,那麼a中位於a之後的元素對於b中的元素b也形成了逆序對,於是對於逆序對(a,b),(假設a的起始下標為sa,結束下標為ea,a的下標為pos)實際上合併成c後會會產生ea-pos+1個逆序對。

也就是說,合併過程中,每次出現一對這樣的(a,b),逆序對數目sum = sum + ea-pos+1 ;

根據這樣的原理,再給予對歸併排序的理解,將上面的計算公式加入到歸併排序中,就可以在o(nlogn)的時間複雜度裡計算出乙個給定數字序列中逆序對的數目。

#include

#define n 100000

using namespace std;

void merge(int arr,int start,int mid,int end,int temp,long

long *count)

else

}while(index1<=mid)

temp[index++] = arr[index1++];

while(index2<=end)

temp[index++] = arr[index2++];

for(int i=0;i

}void mergesort(int arr,int start,int end,int temp,long

long *count)

}int main()

int *temp = new

int[m];

mergesort(a,0,m-1,temp,&count);

delete a;

delete temp;

cout<

0; }

輸入格式為:先輸入乙個數字代表陣列的長度,回車,接下來依次輸入以空格分割的n個陣列元素。輸出就是該陣列的逆序對數目。

歸併排序求逆序對

排序都用qsort了,別的排序演算法不怎麼用,但有些排序的思想很重要。碰到一道求逆序對的題,要用到歸併排序,學習了一下歸併排序。歸併排序是用分治思想,分治模式在每一層遞迴上有三個步驟 分解 將n個元素分成個含n 2個元素的子串行。解決 用合併排序法對兩個子串行遞迴的排序。合併 合併兩個已排序的子串行...

歸併排序求逆序對

我們知道,求逆序對最典型的方法就是樹狀陣列,但是還有一種方法就是merge sort 即歸併排序。實際上歸併排序的交換次數就是這個陣列的逆序對個數,為什麼呢?我們可以這樣考慮 歸併排序是將數列a l,h 分成兩半a l,mid 和a mid 1,h 分別進行歸併排序,然後再將這兩半合併起來。在合併的...

歸併排序求逆序對

現在給定乙個有n個數的數列ai。若對於i j,有ai aj,則稱 i,j 為數列的乙個逆序對。例如,2,3,8,6,1 有五個逆序對,分別是 1,5 2,5 3,4 3,5 4,5 現在請你求出乙個給定數列的逆序對個數。輸入格式 乙個整數t,表示有多少組測試資料。每組測試資料第一行是乙個正整數n 1...