算法导论练习9.3-8 中位数

来源:互联网 发布:谢霆锋会做菜吗 知乎 编辑:程序博客网 时间:2024/05/16 09:53

题目:设X[1..n]和Y[1..n]为两个数组,每个都包含n个已排好序的数。给出一个求数组X和Y中所有2n个元素的中位数的、O(logn)时间的算法。

 

这题是老师布置的作业,一开始我想出的解法如下:

分治法:

1、先分别求出X和Y的中位数

2、比较两个数的大小,如果相等就返回。如果不等的话,去掉较大中位数所在的那个数组的较大的一半,去掉较小的中位数所在的数组的较小的一半

3、在规模减半的两个数组上递归调用。

4、如果一直没有遇到正好相等的情况,那么递归到最后会剩下四个数,则返回第二个数。因为这两个数组都是有n个元素,所以最终返回的必然是2n个数中的下中位数。

 

写了一个程序如下:

 

01 int search(int[] X, int p, int q,
02        int[] Y, int r, int s) {
03     int midx, midy;
04     if ((p + 1 == q) && (r + 1 == s)) {
05         if (X[p] < Y[r])
06             return (X[q] < Y[r]) ? X[q] : Y[r];
07         else
08        return (Y[s] < X[p]) ? Y[s] : X[p];
09     }
10     else {
11         midx = (p + q) / 2;
12         midy = (r + s) / 2;
13         if (X[midx] < Y[midy])
14             return search(X, midx, q, Y, r, midy);
15         else if (X[midx] > Y[midy])
16        return search(X, p, midx, Y, midy, s);
17         else
18        return X[midx];
19     }
20 }

 

但是,仔细揣摩这个算法是有问题的。比如对输入X = {1, 3, 5, 7}, Y = {2, 4, 6, 8}

上述算法会得到中位数是3,而显然正确的结果是4。

 

问题就出在当数组中有偶数个元素时进行的划分上。这时,这个算法并不能保证缩小规模后的数组的下中位数还是原来的下中位数。因为此时缩小规模后两个数组的长度变的不一致了,原来的下中位数可能会跑到上中位数的地方去。

 

解决的办法是:

在递归的过程中,当数组中的元素是偶数时,在一个数组中取上中位数,在另一个数组中取下中位数,并且在整个过程中保持不变。在哪个数组中去上中位数,就一直在那个数组中取上中位数,反之亦然。奇数时的情形依旧。

 

程序如下:

 

//   SearchMiddle.java

 

01 import java.util.Random;
02
03 public class SearchMiddle {
04     static int search(int[] X, int p, int q,
05                       int[] Y, int r, int s) {
06         int midx, midy;
07         if ((p + 1 == q) && (r + 1 == s)) {
08             if (X[p] < Y[r])
09                 return (X[q] < Y[r]) ? X[q] : Y[r];
10             else
11                 return (Y[s] < X[p]) ? Y[s] : X[p];
12         }
13         else {
14             if ((q - p) % 2 == 0) {            // 数组元素为奇数个
15                 midx = (p + q) / 2;
16                 midy = (r + s) / 2;
17             }
18             else {                            // 数组元素为偶数个
19                 midx = (p + q) / 2;
20                 midy = (r + s) / 2 + 1;
21             }
22             if (X[midx] < Y[midy])
23                 return search(X, midx, q, Y, r, midy);
24             else if (X[midx] > Y[midy])
25                 return search(X, p, midx, Y, midy, s);
26             else
27                 return X[midx];
28         }
29     }
30     //快速排序
31     static int Partition(int[] A, int p, int r) {
32         int x = A[r];
33         int i = p - 1;
34         int t;
35         for (int j = p; j <= r-1; j++)
36             if (A[j] <= x) {
37                 i++;
38                 t = A[i];
39                 A[i] = A[j];
40                 A[j] = t;
41             }
42         t = A[i+1];
43         A[i+1] = A[r];
44         A[r] = t;
45         return i + 1;
46     }
47     static void QuickSort(int[] A, int p, int r) {
48         int q;
49         if (p < r) {
50             q = Partition(A, p, r);
51             QuickSort(A, p, q - 1);
52             QuickSort(A, q + 1, r);
53         }
54     }
55     static void QSort(int[] A) {
56         QuickSort(A, 1, A.length - 1);
57     }
58    
59     public static void main(String[] args) {
60         int[] a = new int[101];
61         int[] b = new int[101];
62         int[] c = new int[201];
63         Random rand = new Random(1000);
64         for (int j = 0; j < 50; j++) {
65             for (int i = 1; i < 101; i++) {
66                 a[i] = rand.nextInt(8192);
67                 b[i] = rand.nextInt(8192);
68                 c[i] = a[i];
69                 c[100 + i] = b[i];
70             }
71             QSort(a);
72             QSort(b);
73             QSort(c);
74        
75             int temp = search(a, 1, 100, b, 1, 100);
76             if (temp != c[100]) {
77                 System.out.println("error!");
78                 break;
79             }
80         }
81         System.out.println("finish!");
82     }
83 }

程序中用快排对两个数组合并后进行排序,取第n个元素,这就是所要求得中位数,结果验证这个算法是正确的。

原创粉丝点击