寻找两个排序数组的中位数

来源:互联网 发布:w7怎么设置网络共享 编辑:程序博客网 时间:2024/06/04 08:38

寻找两个排序数组的中位数


中位数保持

从一组数字的中位数两边删除同样多的元素(不管被删除的数字的相对顺序是什么样的),中位数保持。— 尽可以把位于中位数左边和右边的这些数字打乱,只要中位数两边被删除的数目相等就能使中位数保持(是剩下的这些数的中位数)。

Alt text

情景分析

  1. 假设两个已排序的数组,记为A[m]B[n]。设想一下,当能确定这两个数组中比中位数小的数值的个数x以及比中位数大的数值的个数y时,求出min=Min(x,y),那么同时去掉中位数两边(左边的数小于或等于中位数,右边的数大于或等于中位数)任意min个数,中位数保持。

为了便于描述,假设数组的起始坐标是1而不是0。还假设C[m+n]是将A和B组合起来排序了的数组。他的中位数下标记为c。记A的中位数的下标为a,B的中位数的下标为b。记A[a]在C中的下标位置为CaB[a]在C中的下标位置为Cb

首先,当A[a]==B[b]时,C的中位数就是A[a],看图。


Alt text

位于两边的数的个数一定是相等的。

然后,若A[a]B[b],我们总有办法交换集合,使得集合A和B满足A[a]<B[b]
case1: m为奇数,n为奇数。
看图:


Alt text

A[a]<B[b],那么一定有:
A[a]在C中的下标位置Ca最大能排在b所在位置Cb的前面,所以有Caa+b1=m+12+(n+121)=m+n2=c,于是,所有位于a左边的数均小于或等于c-1,均位于C的中位数的左边,他们的个数是m+121=m12
B[b]在C中的下标位置Cb最小能排在a所在位置Ca的后面,所以有Cba+b=m+12+(n+12)=m+n2+1=c+1,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n+12
接下来就需要求出Min(n+12m12)。然后剔除A中的前Min(n+12m12)个数,在B中剔除后Min(n+12m12)个数。中位数保持。

case2: m为偶数,n为偶数。
看图:


Alt text


A[a]<B[b],那么一定有:
A[a]在C中的下标位置Ca最大能排在b所在位置Cb的前面,所以有Caa+b1=m2+(n21)=m+n21=c1,于是,A所有位于橙色方框中的数均小于或等于c-1,位于C的中位数的左边,他们的个数是m2
B[b]在C中的下标位置Cb最小能排在a所在位置Ca的后面,所以有Cba+b=m2+(n2)=m+n2=c,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n2
接下来就需要求出Min(n2m2)。然后剔除A中的前Min(n2m2)个数,在B中剔除后Min(n2m2)个数。中位数保持。

case3: m为偶数,n为奇数。
看图:


Alt text

A[a]<B[b],那么一定有:
A[a]在C中的下标位置Ca最大能排在b所在位置Cb的前面,所以有Caa+b1=m2+(n+121)=m+n+121=c1,于是,A所有位于橙色方框中的数均小于或等于c-1,位于C的中位数的左边,他们的个数是m2
B[b]在C中的下标位置Cb最小能排在a所在位置Ca的后面,所以有Cba+b=m2+(n+12)=m+n+12=c,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n+121=n12
接下来就需要求出Min(n12m2)。然后剔除A中的前Min(n12m2)个数,在B中剔除后Min(n12m2)个数。中位数保持。

case4: m为奇数,n为偶数。

看图:


Alt text

A[a]<B[b],那么一定有:
A[a]在C中的下标位置Ca最大能排在b所在位置Cb的前面,所以有Caa+b1=m+12+(n21)=m+n+121=c1,于是,A所有位于橙色方框中的数均小于或等于c-1,位于C的中位数的左边,他们的个数是m+12
B[b]在C中的下标位置Cb最小能排在a所在位置Ca的后面,所以有Cba+b=m+12+(n2)=m+n+12=c,所以A中位于橙色方框中的所有数都位于C的中位数的右边,他们的个数是n2
接下来就需要求出Min(n2m+12)。然后剔除A中的前Min(n2m+12)个数,在B中剔除后Min(n2m+12)个数。中位数保持。

< header >

#include<iostream>#include<vector>#include<iterator>using namespace std;

< search Middle >

//注意处理的顺序,这个函数很容易把处理的顺序搞错,实现起来比较耗时间来调试。int search_Midlle_in_2A(vector<int>const*  set1, int const &first1, int const& last1,                        vector<int>const*  set2, int const &first2, int const& last2){    int fst1(first1), lst1(last1);    int fst2(first2), lst2(last2);    int  size1(last1 - first1 + 1);    int  size2(last2 - first2 + 1);    //如果一个数值串中的数全部被剔除,那就直接返回另一个数值串的中位数。    //不可能同时出现两个数组大小均为0的情况,所以这里的数组访问是合理的。    if (size1 == 0){ return (*set2)[(fst2 + (size2 + 1) / 2 - 1)]; }    if (size2 == 0){ return (*set1)[(fst1 + (size1 + 1) / 2 - 1)]; }    //计算中位数的位置【直接对应其在数组中的下标】    //这里的下标计算也是合理的。    int Middle1(fst1 + (size1 + 1) / 2 - 1);    int Middle2(fst2 + (size2 + 1) / 2 - 1);    //如果两个数组的中位数相等,这个数的就是他们的中位数。    if ((*set1)[Middle1] == (*set2)[Middle2]) return (*set1)[Middle1];    //使得set1的中位数是较小的一个    if ((*set1)[Middle1] > (*set2)[Middle2]){        //交换集合的指向        vector<int>const *temp = set1;        set1 = set2;        set2 = temp;        //同时交换其他相关的值        Middle1 = (first2 + (size2 + 1) / 2 - 1);        Middle2 = (first1 + (size1 + 1) / 2 - 1);        size1 = (last2 - first2 + 1);        size2 = (last1 - first1 + 1);        fst1 = first2; lst1 = last2;        fst2 = first1; lst2 = last1;    }    int min(0);//本次将要被剔除的元素个数。    if (size1 % 2 == 1 && size2 % 2 == 1){//两个数组都含有奇数个元素。        if (size1 == 1) {//这是唯一的一种特殊情况,如果不做处理就会陷入无限循环。            if (size2 == 1) return (*set1)[fst1];            return (*set1)[fst1] > (*set2)[Middle2 - 1] ? (*set1)[fst1] : (*set2)[Middle2 - 1];        }        min = size1/ 2 ;        if (size1 > size2+2) min = size2/2 ;    }    if (size1 % 2 == 0 && size2 % 2 == 0){//两个数组都含有偶数个元素。        min = size1 / 2;        if (size1 > size2) min = size2/2 ;    }    if (size1 % 2 == 1 && size2 % 2 == 0){//set1含有奇数个元素,set2含有偶数个元素。        min = (size1+1)/ 2;        if (size1 > size2 -1) min = size2 /2;    }    if (size1 % 2 == 0 && size2 % 2 == 1){//set2含有奇数个元素,set1含有偶数个元素。        if (size2 == 1){//这是一种特殊情况,如果不做处理就会陷入无限循环。            return (*set2)[fst2] < (*set1)[Middle1 + 1] ? (*set2)[fst2] : (*set1)[Middle1 + 1];        }        min = size1/2;        if (size1 > size2-1) min = size2/2;    }    //根据中位数保持定理,继续递归。    search_Midlle_in_2A(set1, fst1 + min, lst1, set2, fst2, lst2 - min);}int search_Midlle_in_2A(vector<int> * const set1,vector<int>* const set2){    int size1 = (*set1).size();    int size2 = (*set2).size();    return  search_Midlle_in_2A(set1,0,size1-1,set2,0,size2-1);}

< main >

int main(){    vector<int> set1, set2;    cout << "请输入第一个集合(递增), 按ctrl+z结束输入:" << endl;    copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(set1));    cin.clear();    cin.sync();    cout << "请输入第二个集合(递增), 按ctrl+z结束输入:" << endl;    copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter(set2));    cout<<"中位数是:"<<search_Midlle_in_2A(&set1,&set2)<<endl;    cout << endl;    system("pause");    return 0;}
0 0
原创粉丝点击