设计一个算法求给定的两个有序序列的中位数 (分治算法)

设计一个算法求给定的两个有序序列的中位数

【问题求解】

对于含有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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值