求两个已排序(升序)等长的整数数组所有元素的中位数

     算法课的题目,给定两个整数数组x[], y[],两个数组已被排序(升序),数组长度都是n,求这2n个数的中位数。

     最容易想到的是,新建立以个数组 z[2n],将x[],y[]的所有元素排序放入,然后取中间两个数,不过当数组很大时,效率不行啊。<^_^>,不仅空间复杂度很大,重新排序的话也要不少时间.

    分析:因为两个数组已经排序了,可以找找规律吗?这样就可以直接找出和中位数有关的几个元素(两个???)。若x的最大元素小于y的最小元素(或者y的最大元素小于x的最小元素),答案就出来了。如果把x看成是从x[0]到x[maxIndex]的连续区间(数抽???),y也是如此。那么,两个区间可能有重叠部分,可能完全不重叠,也可能大区间完全包含小区间......

    虽然最终确定应该借鉴二分搜索的思想,但是有很多问题不会证明,只是从同学那里知道应该这样,呵呵。以后再试试证明吧,数学没学好啊。。。。

 

#include 
#include 


/* 比较两个整数[ x and y]大小的函数.
 *   Return values:
 *       1: x > y.
 *       0: x == y.
 *       -1: x < y.
 * */
int compare(int x, int y)
{
    return (x > y) ? 1 : ( (x == y) ? 0 : -1);
}


//这是个简单的排序函数, 你懂得<^_^>.
void sortFour(int a[], int n)
{
    int i, j, temp;
    for (i = 0; i < n; ++i)
    {
        for (j = i + 1; j < n; ++j)
        {
            if (a[i] > a[j])
            {
                temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
    }
}
/* 这个才是主角, 给定两个长度为(maxIndex + 1)的数组x[], y[],
 * 两个数组已被排序(升序). 使用二分的思想求两个数组所有元素的中位数.
 *   因为总元素数为偶数,故中位数由中间的两个数合成。这两个数可能位
 *   于同一个数组里,故每个数组二分时,最后保留两个元素,一共
 *   四个,再排序,取中间两个。
 * */
double findMedian(const int x[], const int y[], int maxIndex)
{
    if (maxIndex < 0)
    {
        //老问题,检查一下
        puts("Wrong length of array!");
        exit(-1);
    }
    int Lx, Ly, Rx, Ry, Mx, My;
    Lx = Ly = 0;
    Rx = Ry = maxIndex;
    
    while ( Lx < (Rx - 1) )//当只剩两个(严格的说,包括少于两个的情况,
                           //额,那就是一个喽)元素时,就跳出. 
    {
        Mx = (Lx + Rx) >> 1;
        /* * * * * * * * * * * * * * * * * * * *
         * 这里有个问题是,当区间长度是偶数时,
         * 比如,8,则Mx = 4,此时这个二分的中
         * 点也可以是5,对y[]也是一样。但是因为
         * 我们是从两边"逼近中间",所以若x是从左
         * 逼近,那么y就是从右边逼近,所以应该My = 5,
         * 而不是4,否则得不到正确的结果.
         * (有点像对称的意思,大概就这样,
         * 现在我还不会证明,见谅<^_^>)
         * * * * * * * * * * * * * * * * * * * */
        if ( ((Ry - Ly + 1) & 1))
        {
            My = (Ly + Ry) >> 1;
        }
        else
        { 
            My = (Ly + Ry + 1) >> 1;
        }
        switch( compare(x[Mx], y[My]) )
        {
            case 0:
            case 1:
                Rx = Mx;
                Ly = My;
                break;
            case -1:
                Lx = Mx;
                Ry = My;
        }
    }

    //最后的四个数,
    int a[4];
    a[0] = x[Lx];
    a[1] = x[Rx];
    a[2] = y[Ly];
    a[3] = y[Ry];

    sortFour(a, 4);//排个序
    
    //结果用double 存放,保留小数.
    double result = (double)(a[1] + a[2]) / 2;
    
    return result;
}


//Application start.
int main(void)
{
    int n = 0;
    int i;
    double result;
    do
    {
        printf("Input the length of array:");
        fflush(stdin);
        scanf("%d", &n);
    } while (n < 1);

    int num_1[n];
    int num_2[n];

    printf("Inpuut the data of group 1:");
    fflush(stdin);
    for (i = 0; i < n; ++i)
    {
        scanf("%d", num_1 + i);
    }

    printf("Inpuut the data of group 2:");
    fflush(stdin);
    for (i = 0; i < n; ++i)
    {
        scanf("%d", num_2 + i);
    }

    result = findMedian(num_1, num_2, n - 1);
    printf("the result is : %.2f", result);

    getch();
    return 0;
}


 

你可能感兴趣的:(C,算法)