题目要求:利用归并排序求得排序过程中出现逆序对的个数。如输入数组长度为5的序列,分别为9·1·0·5·4,得到逆序对的个数为6.可通过以下代码得到结果。(可是POJ不通过,这点我搞不明白,可否有高手看看代码处是否出错,不胜感谢!)

1 #include<stdio.h>
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 之间的整数。)

`实现代码如下:

 

1 #include<stdio.h>
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,到此止步,但自己还是不太完全了解归并排序中的递归过程,只是模糊的认识而已。

 

 

posted on 2010-10-10 23:51  KuSiuloong  阅读(2334)  评论(0编辑  收藏  举报