逆序對 從插入排序到歸併排序

2022-02-20 23:08:28 字數 1744 閱讀 6275

設a[1..n]是乙個包含n個非負整數的陣列。如果在ia[j],則(i,j)就稱為a中的乙個逆序對(inversion)。

a)列出陣列[2,3,8,6,1]的5個逆序。

b)如果陣列的元素取自集合{1,2,...,n},那麼,怎樣的陣列含有最多的逆序對?它包含多少個逆序對?

c)插入排序的執行時間與輸入陣列中逆序對的數量之間有怎樣的關係?說明你的理由。

——《演算法導論》,思考題2-4

逆序對的應用很多,比如各類oj中的逆序對題目:再比如《程式設計之美》1.7光影切割問題解法二的求交點個數。從上面的思考題入手來理解逆序對演算法很簡單,這也是標題中所展示的思路歷程。本文主要面對的是之前對逆序對基本沒接觸和不了解o(nlogn)解法的讀者,可能顯得有些囉嗦。

問題a)直接根據定義可得<2,1>,<3,1>,<8,6>,<8,1>,<6,1>。

問題b)為了逆序對最多,那麼應使任乙個數在所有比它小的數前面,從而構成所有可能逆序,即[n,n-1,...,1],這樣一共有(n-1)+(n-2) + ... + 1 =n(n-1)/2個。

問題c),在插入排序進行時,陣列分為兩部分:已排序部分和待排序部分。每次將待排序部分的第乙個元素插入到已排序部分時,需要找出其插入的位置,並把這之後的已排序元素依次後移。並且,對於乙個元素,插入過程中後移的元素數目就是它在原陣列中它前面的逆序對的數目。這是因為,根據逆序對定義,可以寫出o(n2)的檢測方式,二者是一樣的。

for(i=0;j)

for(i=0;i)

if(a[i]>a[j])

count++;

其實對於問題c,本意並不是告訴讀者使用插入排序來找逆序對:同樣是o(n2)的演算法,這樣做沒有任何改進之處;而是在於啟發對問題d)的解答。

1.在歸併排序中,同樣是對乙個陣列分為兩段處理,在處理這兩段時,並不會影響右段元素與左段元素的逆序關係,只有在歸併時才會改變。

2.歸併時的改變方式和插入排序是類似的:右段中取出元素放在左段其餘所有元素前面時,相當於左段整體後移,後移的元素數就是這個逆序數。

3.由於歸併排序使用的是分治法,將每次歸併的逆序數累加,最後結果就是總的逆序數。並且,歸併排序的時間複雜度是o(nlogn),優於插入排序。

根據以上的**,歸併排序稍作修改,就獲得了時間複雜度為o(nlogn)的尋找逆序對總數的演算法了,下面是乙個簡單示例。

#include    #include    

#define maxnum 65535

#define length 8

static

int data[length] =;

//#define length 5

//static int data[length] =;

int show_out(int *array,int

n);int merge(int *array, int nbegin, int nmid, int

nend)

else

}free(left);

free(right);

show_out(array,length);

return

count;

}int inversion(int *array, int nbegin, int

nend)

return

count;

}int show_out(int *array,int

n) int

main()

逆序對 從插入排序到歸併排序

設a 1.n 是乙個包含n個非負整數的陣列。如果在ia j 則 i,j 就稱為a中的乙個逆序對 inversion a 列出陣列 2,3,8,6,1 的5個逆序。b 如果陣列的元素取自集合 1,2,n 那麼,怎樣的陣列含有最多的逆序對?它包含多少個逆序對?c 插入排序的執行時間與輸入陣列中逆序對的數...

插入排序 歸併排序

插入排序 define len 5 int a len void insertion sort void int i,j,k for j 1 j len j k a j i j 1 while i 0 a i k a i 1 a i i a i 1 k 歸併排序 int a 8 void merge...

插入排序 歸併排序

演算法導論初涉,第一講練習內容 include define n 6 int a n void init 初始化陣列 a i 1 k void output int a,int n void merge int low,int mid,int high while s mid b i a s whi...