在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱爲一個逆序。一個排列中逆序的總數就稱爲這個排列的逆序數。
求逆序數的方法很多。最容易想到的辦法是分別對序列中每一個元素求其逆序數,再求所有元素的逆序數總和,易分析得出這樣的方法其時間複雜度爲O(n2)。
這裏介紹一種分治的方法求逆序數,其思路如下。
我們知道在對序列進行二路歸併排序的時候,要將序列拆分成若干子序列,先將子序列排序,再合併子序列構成最終排序後的序列。二路歸併算法還有一個特點,在進行歸併操作時候的兩個子序列是有序序列,所以,我們可以利用這一點,在歸併子序列的時候,其中的子序列內部的逆序數必然是0,這時候能產生逆序數的情況必然處於子序列之間,即:“位置靠後的子序列”中的元素小於“位置靠前的子序列”的元素。例如,有子序列x:2,4,5;子序列y:1,3,6,顯然,子序列y中的元素1的逆序數爲3,子序列y中的元素3的逆序數爲2,其他元素的逆序數均爲0。通過這樣一種方法,我們可以在序列的二路歸併排序的過程中將序列的逆序數計算出來。故其時間複雜度爲O(nlogn)。
其代碼實現如下:
h1.h
- #ifndef H1_H
- #define H1_H
- #include<string.h>
- #include<ctype.h>
- #include<malloc.h> /* malloc()等 */
- #include<limits.h> /* INT_MAX等 */
- #include<stdio.h> /* EOF(=^Z或F6),NULL */
- #include<stdlib.h> /* atoi() */
- #include<io.h> /* eof() */
- #include<math.h> /* floor(),ceil(),abs() */
- #include<process.h> /* exit() */
- #define MAXSIZE 100
- #define TRUE 1
- #define FALSE 0
- #define OK 1
- #define ERROR 0
- #define INFEASIBLE -1
- /* #define OVERFLOW -2 因爲在math.h中已定義OVERFLOW的值爲3,故去掉此行 */
- typedef int Status; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */
- typedef int Boolean; /* Boolean是布爾類型,其值是TRUE或FALSE */
- #endif
- #include "h1.h"
- int mergeCount(int a[], int low, int center, int high){
- int count;
- int i, j, k;
- if(low >= high){
- return 0;
- }
- int *temp = (int *)malloc(sizeof(int)*MAXSIZE);
- if(!temp){
- printf("Error!Memorry allocation wrong!");
- }
- count = 0;
- for(i=low,j=(center+1),k=0; i<=center&&j<=high; ){
- if(a[i]>a[j]){
- count += (center-i+1);
- temp[k++] = a[j++];
- }
- else{
- temp[k++] = a[i++];
- }
- }
- while(i <= center){
- temp[k++] = a[i++];
- }
- while(j <= high){
- temp[k++] = a[j++];
- }
- for(i=low; i<=high; i++){
- a[i] = temp[i-low];
- }
- free(temp);
- return count;
- }
- int inversionCount(int a[], int low, int high){
- int center;
- if(low < high){
- center = (low+high)/2;
- int rl, rr, r;
- rl = inversionCount(a, low, center);
- rr = inversionCount(a, center+1, high);
- r = mergeCount(a, low, center, high);
- return (rl+rr+r);
- }
- else{
- return 0;
- }
- }
- int main(){
- int a[] = { 12, 3, 7, 10, 14, 18, 19, 2, 11, 16, 17, 23, 25};
- int i, result=0;
- result = inversionCount(a, 1, 12);
- printf("The numbers sorted:\n");
- for(i=1; i<=12; i++){
- printf("%d ", a[i]);
- }
- printf("\nThe inversion count is: %d\n", result);
- return 0;
- }
註上述測試的序列爲:
- {3, 7, 10, 14, 18, 19, 2, 11, 16, 17, 23, 25}排在第一位的12表示元素個數,其最終逆序數爲13.