分治法 ——查找问题 —— 寻找两个等长有序序列的中位数

本文介绍了一种高效算法,用于找出两个等长有序序列的中位数。通过不断缩小搜索范围,最终确定中位数值,适用于数据分析与算法优化场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

查找问题:

  • 问题一:寻找两个等长有序序列的中位数

问题描述:对于一个长度为n的有序序列(假设均为升序序列)a[0 … n-1] ,处于中间位置的元素称为a的中位数。

例如,若序列a=(11,13,15,17,19),其中位数为15;
若序列b=(2,4,6,8,24),其中位数为6

两个等长有序序列的中位数是含有它们所有元素的有序序列的中位数,如上a,b序列的中位数为11

分析思路:

对于含有n个,元素的有序序列a[s … t ],

当n为奇数时,中位数出现在m=(s+t)/2;
当n为偶数时,中位数出现在m=(s+t)/2上中位和m=(s+t)/2+1下中位;在这里假设只取上中位

(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[a … m],取后半部分时(看元素个数),
若为奇数,则(s+t)/2
若为偶数,则(s+t)%2==1,则后半部分为a[m+1 …t ]

在这里插入图片描述
若序列a=(11,13,15,17,19),其中位数为15;
若序列b=(2,4,6,8,24),其中位数为6

在这里插入图片描述
代码一:

#include<stdio.h>

void prepart(int &s,int &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 mid(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 、b中位数 
		m2=(s2+t2)/2;
		if(a[m1]==b[m2])
		return a[m1];
		if(a[m1]<b[m2]){
			postpart(s1,t1);  //取a后半部分
			prepart(s2,t2);  //取b前半部分
			return mid(a,s1,t1,b,s2,t2); 
		}
		else{
			prepart(s1,t1);  //取a半部分
			postpart(s2,t2); //取b后半部分
			return mid(a,s1,t1,b,s2,t2);
		} 
	 } 
} 

int main(){
	int a[]={11,13,15,17,19};
	int b[]={2,4,6,8,24};
	printf("中位数:%d\n",mid(a,0,4,b,0,4)); 
}


求两个序列中位数可用循环语句来替换,等价的非递归算法

代码二:

#include<stdio.h>

void prepart(int &s,int &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 mid(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,24};
	printf("中位数:%d\n",mid(a,b,5)); 
}


在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值