poj2299 归并排序求逆序数

题意很简单,求QuickSort最坏情况下的交换次数。理解以后知道应该是一个求序列的逆序对问题。

发现归并排序nlog(n)的排序速度很不错,而求在排序的过程中,有个归并过程merge(),这里是将两个有序数列归并为一个有序数列,在归并的过程中,很容易就能够计算逆序对个数,所以可以很快解决这个问题。

即:对于数列[l, mid] [mid + 1, r]的合并,i 从l开始循环,j从mid + 1开始循环,如果遇到a[i] > a[j] 则出现逆序,可以将a[j]放入辅助数组,同时j++,那么和a[j]逆序的数就有mid-i+1个,因为序列是有序的[i, mid]的所有的数都是大于a[j]的。代码如下。有重温了归并的写法与思想。。

代码
   
     
1 #include < stdio.h >
2 #include < string .h >
3 #include < string .h >
4 #include < stdlib.h >
5 #include < math.h >
6
7 #include < iostream >
8   using namespace std;
9
10 #define NN 500004
11 #define NL 1000
12
13 __int64 res;
14 int b[NN]; // 中间辅助数组
15
16 void copy( int a[], int l, int r){
17 int i;
18 for (i = l; i <= r; i ++ ){
19 a[i] = b[i];
20 }
21 }
22 void merge( int a[], int l, int mid, int r){
23 int i = l;
24 int j = mid + 1 ;
25 int k = l;
26 while (i <= mid && j <= r){
27 if (a[i] < a[j]){
28 b[k ++ ] = a[i];
29 i ++ ;
30 } else {
31 b[k ++ ] = a[j];
32 j ++ ;
33 res += mid - i + 1 ;
34 }
35 }
36 while (i <= mid){
37 b[k ++ ] = a[i];
38 i ++ ;
39 }
40 while (j <= r){
41 b[k ++ ] = a[j];
42 j ++ ;
43 }
44 }
45
46 void mergeSort( int a[], int l, int r){
47 // 归并排序
48 if (l < r){
49 int mid = (l + r) >> 1 ;
50 mergeSort(a, l, mid);
51 mergeSort(a, mid + 1 , r);
52 merge(a, l, mid, r);
53 copy(a, l, r);
54 }
55 }
56 int main() {
57 int n, i;
58 int f[NN];
59 while (scanf( " %d " , & n) != EOF){
60 if (n == 0 ) break ;
61 for (i = 1 ; i <= n; i ++ ){
62 scanf( " %d " , & f[i]);
63 }
64 res = 0 ;
65 mergeSort(f, 1 , n);
66 printf( " %I64d\n " , res);
67 }
68 return 0 ;
69 }
70

 

你可能感兴趣的:(归并排序)