分治法求解逆序数

   在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数

      求逆序数的方法很多。最容易想到的办法是分别对序列中每一个元素求其逆序数,再求所有元素的逆序数总和,易分析得出这样的方法其时间复杂度为O(n2)。

      这里介绍一种分治的方法求逆序数,其思路如下。

       我们知道在对序列进行二路归并排序的时候,要将序列拆分成若干子序列,先将子序列排序,再合并子序列构成最终排序后的序列。二路归并算法还有一个特点,在进行归并操作时候的两个子序列是有序序列,所以,我们可以利用这一点,在归并子序列的时候,其中的子序列内部的逆序数必然是0,这时候能产生逆序数的情况必然处于子序列之间,即:“位置靠后的子序列”中的元素小于“位置靠前的子序列”的元素。例如,有子序列x:2,4,5;子序列y:1,3,6,显然,子序列y中的元素1的逆序数为3,子序列y中的元素3的逆序数为2,其他元素的逆序数均为0。通过这样一种方法,我们可以在序列的二路归并排序的过程中将序列的逆序数计算出来。故其时间复杂度为O(nlogn)。

      其代码实现如下:

     h1.h

[cpp]  view plain copy
  1. #ifndef H1_H  
  2. #define H1_H  
  3.   
  4. #include  
  5. #include  
  6. #include /* malloc()等 */  
  7. #include /* INT_MAX等 */  
  8. #include /* EOF(=^Z或F6),NULL */  
  9. #include /* atoi() */  
  10. #include /* eof() */  
  11. #include /* floor(),ceil(),abs() */  
  12. #include /* exit() */  
  13.   
  14. #define MAXSIZE 100  
  15. #define TRUE 1  
  16. #define FALSE 0  
  17. #define OK 1  
  18. #define ERROR 0  
  19. #define INFEASIBLE -1  
  20. /* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */  
  21. typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */  
  22. typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */  
  23.   
  24.   
  25. #endif  
InversionCount.c

[cpp]  view plain copy
  1. #include "h1.h"  
  2.   
  3. int mergeCount(int a[], int low, int center, int high){  
  4.   
  5.     int count;  
  6.     int i, j, k;  
  7.   
  8.     if(low >= high){  
  9.         return 0;  
  10.     }  
  11.   
  12.     int *temp = (int *)malloc(sizeof(int)*MAXSIZE);  
  13.     if(!temp){  
  14.         printf("Error!Memorry allocation wrong!");  
  15.     }  
  16.   
  17.     count = 0;  
  18.     for(i=low,j=(center+1),k=0; i<=center&&j<=high; ){  
  19.         if(a[i]>a[j]){  
  20.             count += (center-i+1);  
  21.             temp[k++] = a[j++];  
  22.         }  
  23.         else{  
  24.             temp[k++] = a[i++];  
  25.         }  
  26.     }  
  27.     while(i <= center){  
  28.         temp[k++] = a[i++];  
  29.     }  
  30.     while(j <= high){  
  31.         temp[k++] = a[j++];  
  32.     }  
  33.   
  34.     for(i=low; i<=high; i++){  
  35.         a[i] = temp[i-low];  
  36.     }  
  37.   
  38.     free(temp);  
  39.   
  40.     return count;  
  41. }  
  42.   
  43. int inversionCount(int a[], int low, int high){  
  44.   
  45.     int center;  
  46.   
  47.     if(low < high){  
  48.         center = (low+high)/2;  
  49.         int rl, rr, r;  
  50.         rl = inversionCount(a, low, center);  
  51.         rr = inversionCount(a, center+1, high);  
  52.         r = mergeCount(a, low, center, high);  
  53.         return (rl+rr+r);  
  54.     }  
  55.     else{  
  56.         return 0;  
  57.     }  
  58. }  
  59.   
  60. int main(){  
  61.   
  62.     int a[] = { 12, 3, 7, 10, 14, 18, 19, 2, 11, 16, 17, 23, 25};  
  63.   
  64.     int i, result=0;  
  65.   
  66.     result = inversionCount(a, 1, 12);  
  67.   
  68.     printf("The numbers sorted:\n");  
  69.     for(i=1; i<=12; i++){  
  70.         printf("%d  ", a[i]);  
  71.     }  
  72.     printf("\nThe inversion count is: %d\n", result);  
  73.   
  74.     return 0;  
  75. }  

注上述测试的序列为:
[cpp]  view plain copy
  1. {3, 7, 10, 14, 18, 19, 2, 11, 16, 17, 23, 25}排在第一位的12表示元素个数,其最终逆序数为13.

你可能感兴趣的:(算法)