求两个已序数组的中位数

来源:互联网 发布:五子棋游戏c语言代码 编辑:程序博客网 时间:2024/04/29 10:35

本文转自:http://dsqiu.iteye.com/blog/1715280

题目:

已知两个数组x[]与y[],各有n个元素,并且也已经以从小到大的顺序排好,编写一 个程序,用少于n次比较找出x[]与y[]合并后的中位数。
说明:
因为x[]与y[]都已经排好,而且各有n个元素,因此一般最自然的想法就是把x[]与 y[]做合并的工作,一直合并到得出第a个元素时,这就是中位数了,这一共会用n次比较。 注意,为方便起见,把中位数定成在中间的两个及其中之一,这是个方便的定义,因为x[] 与y[]合起来有2n个元素,因此真正的中位数的定义应该是第n与第n+1个元素的平均数; 所以为了方便,只要求找出第n个或第n+1个元素即可。
上面提到的,用合并的方法会用到与II成正比的比较次数,并不是所期望的做法,所希望的,是要比n少很多的做法。可能会想到的改善是:因为x[]与y[]是排好的,可以用 x[]的中间元素,例如x[mid],通过二分查找法找出它在y[]数组中的位置,例如:
y[i] < x [mid] < y [i + 1]
所以在合并起来之后,x[mid]前面的元素就有mid+i+1个,如果这个值大于n,那么中位数就必定在这mid+i+1个元素内,因此x[mid+l]〜x[n-1],y[i+1]〜y[n-1]都可以去掉,接着在x[0]〜x[mid],y[0]〜y[i]之间找中位数就行了。但若mid+i+1比n小,在合并起来后中 位数在元素多的那一半,所以把x[0]〜x[mid],y[0]〜y[i]去掉,而在x[mid+1]〜x[n-1],y[i+1]〜x[n-1]之间找中位数。反复这个过程,就不难找出中位数了。需要多少次比较呢?大约与 (log2n)^2成正比,道理为何请读者自己证明。
事实上,问题还可以做得更好,而且也不必那么复杂,在与log2n成正比的比较次数
之下就可以找出中位数的。


解答:
其实在问题说明中的(log2n)2方法已经差不多可以说是涉及到重点所在了,它之所以 到不了 log2ii的境界,是因为每次所去掉的、不可能包含了中位数的元素个数不够多。为了要去掉足够多的、不适合的元素,要把那个办法动一点手脚才行。想法是,一次要去掉 将近一半的元素(就像是二分搜寻法一样),大约log2n次之后,就可以得到结果了。
首先,拿x[mid_x]与y[mid_y]这两个在x[]与y[]中央的元素比较。如果x[mid_x]比 y[mid_y]小,那么在合并后的结果中x[mid_x]就排在y[mid_y]前面,而且中位数一定在这 两者之间。原因是在x[]中,在x[mid_x]之前有n/2个元素,同理,y[]中在y[mid_y]之前也有n/2个元素,所以合并后至少会包含了所有小于等于x[mid一x]与y[mid_y]的元素,这样就有了 n个。但因为x[mid_x]小于等于y[mid_y+1],所以x[]中比x[mid_x]大的部分也有 若干元素落在y[mid_j]的前面,所以合并后在y[mid_j]之前就有不止n个元素。换句话说, 中位数一定在y[mid_y]之前。正因为如此,在y[]中比y[mid_j]大的元素中就不可能含有中位数了,所以y[mid_y+1]〜y[n-1]的元素就可以去掉,只留下y[0]〜y[mid_y],这样y[]中 就被去掉了差不多一半的元素。
再看x[mid_x]。在x[]中比它小的不足n/2个元素,可以把x[]中x[0]~x[mid_x-1]的元素去掉,因此x[]几乎去掉了一半的元素。

代码实现:
void  sort(int [], int);int  median(int x[], int y[], int n){     int  first_X = 0;        /* lower element of x[]     */     int  first_Y = 0;        /* lower element of y[]     */     int  last_X  = n-1;      /* higher element of x[]    */     int  last_Y  = n-1;      /* higher element of y[]    */     int  count   = 0;        /* # of smaller items elim. */     int  mid_X, mid_Y;       /* middle element pointers  */     int  number;             /* # of elements left       */     int  z[4];               /* working array            */     while ((last_X - first_X > 1) || (last_Y - first_Y > 1)) {          mid_X = (first_X + last_X)/2;  /* get mid ptrs  */          mid_Y = (first_Y + last_Y)/2;          if (x[mid_X] <= y[mid_Y]) {                  count   += (mid_X - first_X); /* inc. count*/               first_X =  mid_X; /* elim. lower half x[]  */               last_Y  =  mid_Y; /* elim. higher half x[] */          }          else {               count   += (mid_Y - first_Y);               first_Y =  mid_Y; /* elim. lower half y[]  */               last_X  =  mid_X; /* elim. higher half x[] */          }     }     for (number = 0; first_X <= last_X; first_X++)          z[number++] = x[first_X];  /* collect remainder */     for ( ; first_Y <= last_Y; first_Y++)          z[number++] = y[first_Y];     sort(z, number);         /* sort them                */     return z[n-count-1];     /* pick up appropriate item */}/* ------------------------------------------------------ *//* FUNCTION  sort :                                       *//*    Special routine to sort small arrays with 2, 3 and  *//* 4 elements.                                            *//* ------------------------------------------------------ */#define  SWAP(x, y)  { temp = x; x = y; y = temp; }void  sort(int z[], int n){     int  temp;     switch (n) {          case 4 : if (z[0] >= z[3])  SWAP(z[0], z[3]);                   if (z[1] >= z[3])  SWAP(z[1], z[3]);                   if (z[2] >= z[3])  SWAP(z[2], z[3]);          case 3 : if (z[0] >= z[2])  SWAP(z[0], z[2]);                   if (z[1] >= z[2])  SWAP(z[1], z[2]);          case 2 : if (z[0] >= z[1])  SWAP(z[0], z[1]);     }}/* ------------------------------------------------------ */#include  <stdio.h>void  main(void){     int  x[] = { 1, 3, 6,  7,  8,  9, 10};     int  y[] = { 2, 4, 5, 11, 12, 13, 14};     int  n   = sizeof(x)/sizeof(int);     int  i;     printf("\nMedian of Two Sorted Arrays");     printf("\n===========================");     printf("\n\nArray #1     Array #2");     printf(  "\n--------     --------");     for (i = 0; i < n; i++)          printf("\n%6d%13d", x[i], y[i]);     printf("\n\nMedian is %d", median(x, y, n));}





原创粉丝点击