@Author: 张海拔
@Update: 2014-01-14
@Link: http://www.cnblogs.com/zhanghaiba/p/3520089.html
1 /* 2 *Author: ZhangHaiba 3 *Date: 2014-1-15 4 *File: inverse_number.c 5 * 6 *this demo shows two method solving inverse number problem 7 */ 8 9 #include <stdio.h> 10 #define N 512 11 #define INF 0x7fffffff; //value of sentinel 12 int array[N]; 13 int left_tmp[N/2+10]; 14 int right_tmp[N/2+10]; 15 16 //public 17 int inverse_number_cnt(int *, int); 18 int inverse_number_cnt2(int *, int); 19 void merge_sort(int *, int, int, int *); 20 void set_array(int *, int); 21 void show_array(int *, int); 22 23 24 int main(void) 25 { 26 int n; 27 28 scanf("%d", &n); 29 set_array(array, n); 30 int ans; 31 ans = inverse_number_cnt(array, n); 32 printf("%d ", ans); 33 ans = inverse_number_cnt2(array, n); 34 printf("%d ", ans); 35 return 0; 36 } 37 38 int inverse_number_cnt(int *a, int n) 39 { 40 int i, j, cnt = 0; 41 42 for (i = 0; i < n-1; ++i) 43 for (j = i+1; j < n; ++j) 44 if (a[i] > a[j]) 45 ++cnt; 46 return cnt; 47 } 48 49 50 //modify merge_sort: 51 //add variable cnt 52 //add code "*cnt = left_len - i;" 53 void merge_sort(int *a, int l, int r, int *cnt) 54 { 55 if (l >= r) return; 56 else { 57 int m = l + (r-l)/2; 58 merge_sort(a, l, m, cnt); 59 merge_sort(a, m+1, r, cnt); 60 int left_len = m-l+1, right_len = r-m, i, j = l; 61 for (i = 0; i < left_len; ++i, ++j) 62 left_tmp[i] = a[j]; 63 left_tmp[i] = INF; 64 for (i = 0; i < right_len; ++i, ++j) 65 right_tmp[i] = a[j]; 66 right_tmp[i] = INF; 67 for (i = j = 0; l <= r; ++l) { 68 if (left_tmp[i] <= right_tmp[j]) 69 a[l] = left_tmp[i++]; 70 else { 71 a[l] = right_tmp[j++]; 72 *cnt += left_len - i; 73 } 74 } 75 } 76 } 77 78 79 int inverse_number_cnt2(int *a, int n) 80 { 81 int l = 0, r = n-1, cnt = 0; 82 83 merge_sort(a, l, r, &cnt); 84 return cnt; 85 } 86 87 88 void set_array(int *a, int n) 89 { 90 int i; 91 92 for (i = 0; i < n; ++i) 93 scanf("%d", a+i); 94 } 95 96 97 void show_array(int *a, int n) 98 { 99 int i; 100 101 for (i = 0; i < n; ++i) 102 printf(i == n-1 ? "%d " : "%d ", a[i]); 103 }
逆序对的定义:序列A中,当位置i < j,而对应值a[i] > a[j],则称(i, j)构成序列A的一个逆序对。
解法一中,按照定义,通过两个for循环即可求出逆序对数。
即以第i个的元素为起点,j从i+1开始到n-1结束按定义进行验证,从而统计逆序对的个数,显然i的范围是[0, n-2]。
显然解法一的时间复杂度是O(n^2)。
解法二的所用函数几乎就是调用了一个纯粹的归并排序,目的通过计数器cnt的地址来修改cnt,做完归并排序后返回。
这个解法求逆序对数的原理是:对于某一次的归并(有序表的合并),类似二叉树的后序遍历,归并时当右子数组某个元素k进入根数组时,此时左子数组中,下标为i的元素以及它后面的所有元素都与k构成逆序对(左子数组的下标均<左子数组任何一个元素的下标,而k能进入根数组则说明它的值比左子数组剩下的所有元素都小,因此k的下标与上述元素的下标,均构成逆序对),所以有逆序对数要增加left_len - i,即:*cnt += left_len - i。