设计一个算法求给定的两个有序序列的中位数
【问题求解】
对于含有n个元素的有序序列a[s…t],当n为奇数时,中位数出现在m=a[(s+t)/2]处;当n为偶数时,中位数下标有m=[(s+t)/2]和m=[(s+t)/2]两个。为了简单,这里仅考虑中位数下标为m=[(s+t)/2]
利用二分法求含有n个有序元素的序列a、b的中位数的过程如下:
(1)分别求出a、b的中位数a[m1]、b[m2]。
(2)若a[m1]=b[m2],则a[m1]或b[m2]即为所求的中位数,算法结束。
(3)若a[m1]<b[m2],则舍弃a的前半部分(较小的一半,同时舍弃序列b中后半部分(较大的一般),要求舍弃的长度相等。
(4)若a[m1]>b[m2],则舍弃序列a中的后半部分(较大的一般),同时舍弃序列b的前半部分(较小的一半),要求舍弃的长度相等。
在保留的两个升序序列中重复上述过程直到两个序列中只含有一个元素时候为止,较小者即为所求的中位数。
为了保证每次索取的两个子序列等长,对于a[s…t],m=(s+t)/2,若取前半部分,则为a[s…m],在取后半部分时要区分a中的元素个数为奇数还是偶数,若为奇数(满足(s+t)%20的条件),则后半部分为a[m…t],若为偶数(满足(s+t)%21的条件),则后半部分为a[m+1…t]
例如,求a=(11,13,15,17,19)、b=(2,4,6,8,20)两个有序序列的中位数的过程如下:
代码实现:
#include<stdio.h>
void prepart(int &s,int &t) //求a[s..t]序列的前半个子序列
{
int m=(s+t)/2;
t=m;
}
void postpart(int &s,int &t){
int m=(s+t)/2;
if((s+t)%2==0) //序列中有奇数个元素
s=m;
else //序列中有偶数个元素
s=m+1;
}
int medium(int a[],int s1,int t1,int b[],int s2,int t2){
int m1,m2;
if(s1==t1&&s2==t2){
return a[s1]<b[s2]?a[s1]:b[s2];
}
else{
m1=(s1+t1)/2; //求a的中位数
m2=(s2+t2)/2; //求b的中位数
if(a[m1]==b[m2]) //两个数组的中位数相等时返回该中位数
return a[m1];
if(a[m1]<b[m2]){
postpart(s1,t1);
prepart(s2,t2);
return medium(a,s1,t1,b,s2,t2);
}
else
{
prepart(s1,t1); //a取前半部分
postpart(s2,t2); //b取后半部分
return medium(a,s1,t1,b,s2,t2);
}
}
}
int main(){
int a[]={11,13,15,17,19};
int b[]={2,4,6,8,20};
printf("中位数:%d\n",medium(a,0,4,b,0,4));
return 0;
}
其中求a、b两个有序序列的中位数的算法也可以用循环语句来天,等价的非递归算法如下:
#include<stdio.h>
void prepart(int &s,int &t) //求a[s..t]序列的前半个子序列
{
int m=(s+t)/2;
t=m;
}
void postpart(int &s,int &t){
int m=(s+t)/2;
if((s+t)%2==0) //序列中有奇数个元素
s=m;
else //序列中有偶数个元素
s=m+1;
}
int medium(int a[],int b[],int n)
{
int s1,t1,m1,s2,t2,m2;
s1=0;
t1=n-1;
s2=0;
t2=n-1;
while(s1!=t1||s2!=t2){
m1=(s1+t1)/2;
m2=(s2+t2)/2;
if(a[m1]==b[m2])
return a[m1];
if(a[m1]<b[m2]){
postpart(s1,t1);
prepart(s2,t2);
}
else{
prepart(s1,t1);
postpart(s2,t2);
}
}
return a[s1]<b[s2]?a[s1]:b[s2];
}
int main(){
int a[]={11,13,15,17,19};
int b[]={2,4,6,8,20};
printf("中位数:%d\n",medium(a,b,5));
return 0;
}
【算法分析】对于含有n个元素的有序序列a和b,设调用medium(a,0,n-1,b,0,n-1)求中位数的执行时间为T(n)则有以下递推式:
T(n)=1 当n=1时
T(n)=2T(n/2)+1 当n>1时
得出T(n)=O(log2 n)