算法导论练习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 }
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 }
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个元素,这就是所要求得中位数,结果验证这个算法是正确的。
- 算法导论练习9.3-8 中位数
- 算法导论 9.3-8 求两个数组的中位数
- 算法导论 9.3-8 求两个数组的中位数
- 算法导论 9.3-8 求两个数组的中位数
- 【算法导论】中位数
- 算法导论 9.3-8 寻找数组X[1..n],Y[1...n] 合并后的中位数
- 求两个等长已排序数组的中位数(算法导论习题9.3-8)
- 算法导论学习之加权中位数
- 算法导论-------------中位数和顺序统计学
- 算法导论 练习 2.1
- 算法导论 练习 2.2
- 算法导论 9.3-7 O(n)时间求最接近中位数的k个数
- 算法导论第九章9.3.7----最接近中位数的k个数
- 【算法导论】中位数和顺序统计量之选择算法
- 《算法导论》练习28.1-5
- 算法导论 练习 2.3-1
- 算法导论 练习 2.3-2
- 算法导论 练习 2.3-3
- 想翻译flex与bison这书
- Linq To Xml 备忘录3(使用Namespace的查询)
- stray '/161' in program
- htaccess
- JAVA
- 算法导论练习9.3-8 中位数
- 安装vim 软件源问题
- windows下PHP调用执行桌面程序的方法
- PHP中调用外部程序,及其参数与返回值
- 用API函数区分U盘和移动硬盘
- 调试linux内核总览
- Android学习笔记3——学习intent
- 用PHP执行shell命令
- Android学习笔记4——学习4个基本控件