题目要求:利用归并排序求得排序过程中出现逆序对的个数。如输入数组长度为5的序列,分别为9·1·0·5·4,得到逆序对的个数为6.可通过以下代码得到结果。(可是POJ不通过,这点我搞不明白,可否有高手看看代码处是否出错,不胜感谢!)
2 #include < stdlib.h >
3 #define MAX 50000
4 /* *
5 * 0 <= p <= q < r, subarray array[p..q] and array[q+1..r] are already sorted.
6 * the merge() function merges the two sub-arrays into one sorted array.
7 */
8 int count = 0 ;
9 void Merge( int array[], int p, int q, int r)
10 {
11 int i,k;
12 int begin1,end1,begin2,end2;
13 int * temp = ( int * )malloc((r - p + 1 ) * sizeof ( int ));
14 begin1 = p;
15 end1 = q;
16 begin2 = q + 1 ;
17 end2 = r;
18 k = 0 ;
19
20 while ((begin1 <= end1) && ( begin2 <= end2))
21 {
22 if (array[begin1] <= array[begin2])
23 {
24 temp[k] = array[begin1];
25 begin1 ++ ;
26
27 }
28 else
29 {
30 temp[k] = array[begin2];
31 begin2 ++ ;
32 // count++;
33 /*
34 *
35 *求逆序对,当array[begin1]中的数比array[begin2]中的数大时;
36 *那么可以推出此数后面的数和array[begin2]这个数大;
37 */
38 count += end1 + 1 - begin1;
39
40 }
41 k ++ ;
42
43 }
44
45 while (begin1 <= end1)
46 {
47 temp[k ++ ] = array[begin1 ++ ];
48
49 }
50
51 while (begin2 <= end2)
52 {
53 temp[k ++ ] = array[begin2 ++ ];
54
55 }
56
57 for (i = 0 ;i < (r - p + 1 );i ++ )
58 array[p + i] = temp[i];
59
60 free(temp);
61
62 }
63 /* *
64 归并操作
65 */
66 void MergeSort( int array[], int first, int last)
67 {
68 int mid = 0 ;
69 if (first < last)
70 {
71 mid = (first + last) / 2 ;
72 MergeSort(array,first,mid);
73 MergeSort(array,mid + 1 ,last);
74 Merge(array,first,mid,last);
75 }
76
77 }
78
79 int main()
80 {
81 int i;
82 int array[MAX];
83 int input;
84 scanf( " %d " , & input);
85 while (input != 0 )
86 {
87 for (i = 0 ;i < input;i ++ )
88 {
89 scanf( " %d " , & array[i]);
90 }
91 MergeSort(array, 0 ,input - 1 );
92 /* for(i=0;i<input;i++)
93 {
94 printf("%d ",array[i]);
95 }
96 */
97 printf( " %d\n " ,count);
98 count = 0 ;
99
100 scanf( " %d " , & input);
101 }
102
103 return 1 ;
104 }
Input:
5
9
1
0
5
4
3
1
2
3
10
2
1
6
5
7
9
11
12
3
8
2
11
11
0
Output:
1|6
2|0
3|11
4|0
以上4项测试结果没错误。(只通过这几项测试不能证明什么,真的...)
************************************************************分割线**********************************************************
`通过分析别人的代码和老师的提示,上面的代码运行是没错的,不过当测试的数据长度在500,000数量级上时,上述代码数据溢出。
`我们通过Int64类型来定义整形数(Int64 值类型表示值介于 -9,223,372,036,854,775,808 到 +9,223,372,036,854,775,807 之间的整数。)
`实现代码如下:
2
3
4 /* *
5 * 0 <= p <= q < r, subarray array[p..q] and array[q+1..r] are already sorted.
6 * the merge() function merges the two sub-arrays into one sorted array.
7 */
8 __int64 count;
9 __int64 a[ 500005 ];
10 __int64 temp[ 500005 ];
11 // 防止数据溢出
12 void Merge( int p, int q, int r)
13 {
14 int i,k;
15 int begin1,end1,begin2,end2;
16 k = p;
17 begin1 = p;
18 end1 = q;
19 begin2 = q + 1 ;
20 end2 = r;
21
22
23 while ((begin1 <= end1) && ( begin2 <= end2))
24 {
25 if (a[begin1] <= a[begin2])
26 {
27 temp[k] = a[begin1];
28 begin1 ++ ;
29
30 }
31 else
32 {
33 temp[k] = a[begin2];
34 begin2 ++ ;
35 // count++;
36 /*
37 *
38 *求逆序对,当array[begin1]中的数比array[begin2]中的数大时;
39 *那么可以推出此数后面的数和array[begin2]这个数大;
40 */
41 count += end1 - begin1 + 1 ;
42
43 }
44 k ++ ;
45
46 }
47
48 while (begin1 <= end1)
49 {
50 temp[k ++ ] = a[begin1 ++ ];
51
52 }
53
54 while (begin2 <= end2)
55 {
56 temp[k ++ ] = a[begin2 ++ ];
57
58 }
59
60 for (i = p;i <= r;i ++ ) // 把合并后的数组还原
61
62 a[i] = temp[i];
63
64 }
65
66
67
68 /* *
69 归并操作
70 */
71 void MergeSort( int first, int last)
72 {
73 int mid = 0 ;
74 if (first < last)
75 {
76 mid = (first + last) / 2 ;
77 MergeSort(first,mid);
78 MergeSort(mid + 1 ,last);
79 Merge(first,mid,last);
80 }
81
82 }
83
84 int main()
85 {
86 int i;
87 int input;
88 scanf( " %d " , & input);
89 while (input != 0 )
90 {
91 count = 0 ;
92 for (i = 0 ;i < input;i ++ )
93 {
94 scanf( " %I64d " , & a[i]);
95 }
96
97 MergeSort( 0 ,input - 1 );
98
99 printf( " %I64d\n " ,count);
100
101
102
103 scanf( " %I64d " , & input);
104 }
105
106
107 return 1 ;
108 }
PS:上面代码的改进之处
1,使用了int64定义整数类型,使得输入的整数型能满足系统测试的数据长度。
2,提前定义了备用数组temp,而不需要像第一个代码中每次归并都要开辟一个数组空间。(有好处有坏处,在这里是好处)
3,通过把数组a和temp变为全局变量,而不需要在方法间传递数组参数。
4,到此止步,但自己还是不太完全了解归并排序中的递归过程,只是模糊的认识而已。