减治法问题1
1 、减治法的设计思想:
1) 原问题的解只存在于其中一个较小规模的子问题中;
(2) 原问题的解与其中一个较小规模的解之间存在某种确定的对应关系。
2、应用减治法(例如减半法)得到的算法通常具有如下递推式:
3、举一个简单的例子:两个序列的中位数
问题描述:一个长度为n(n≥1)的升序序列S,处在第n/2个位置的数称为序列S的中位数 。两个序列的中位数是他们所有元素的升序序列的中位数。现有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列的中位数。
A={11, 13, 15, 17, 19}, B={2, 4, 10, 15, 20}
U={2,4,10,11,13,15,15,17,19,20}
想法:
分别求出两个序列的中位数,记为a和b;比较a和b,有下列三种情况: ① a = b:则a即为两个序列的中位数; ② a < b:则中位数只能出现在a和b之间,在序列A中舍弃a之前的元素得到序列A1,在序列B中舍弃b之后的元素得到序列B1; ③ a > b:则中位数只能出现在b和a之间,在序列A中舍弃a之后的元素得到序列A1,在序列B中舍弃b之前的元素得到序列B1; 在A1和B1中分别求出中位数,重复上述过程,直到其中一个序列只有一个元素,该元素即为所求即为所求。
执行步骤:
步骤 | 操作说明 | 序列A | 序列B |
1 | 初始序列 | {11, 13, 15, 17, 19} | {2, 4, 10, 15, 20} |
2 | 分别求中位数 | {11, 13, 15, 17, 19} | {2, 4, 10, 15, 20} |
3 | 15>10,结果在[10, 15]之间 | 舍弃15之后元素,{11,13,15} | 舍弃10之前元素,{10,15,20} |
4 | 分别求中位数 | {11,13,15} | {10,15,20} |
5 | 13<15,结果在[11, 15]之间 | 舍弃13之前元素,{13,15} | 舍弃15之后元素,{10,15} |
6 | 分别求中位数 | {13,15} | {10,15} |
7 | 10<13,结果在[10, 13]之间 | 舍弃13之后元素,{13} | 舍弃10之前元素,{10,15} |
8 | 长度为1, 即为所求 | {13} | {10,15} |
简单的根据想法和执行步骤写出的代码如下:
//两个序列的中位数
#include<stdio.h>
#include <iostream>
using namespace std;
int FindMid(int a[],int b[],int n)
{
int s1,e1,s2,e2,mid1,mid2;
s1=0;s2=0;e1=n-1;e2=n-1;
while(s1<e1 && s2<e2)
{
mid1 = (s1+e1)/2;
mid2 = (s2+e2)/2;
if(a[mid1] == b[mid2])
return a[mid1];
if(a[mid1] < b[mid2])
{
if((s1+e1)%2 == 0)
s1 = mid1;
else
s1 = mid1+1;
e2 = mid2;
}
else
{
if((s2+e2)%2 == 0)
s2 = mid2;
else
s2 = mid2+1;
e1 = mid1;
}
}
if(a[s1] < b[s2])
return a[s1];
else
return b[s2];
}
int main()
{
int a[10001],b[10001];
int n;
int i,j;
cout<<"请输入两个有序序列的个数:"<<endl;
cin>>n;
cout<<"请输入第一个有序序列:"<<endl;
for(i=0;i<n;i++)
cin>>a[i];
cout<<"请输入第二个有序序列:"<<endl;
for(j=0;j<n;j++)
cin>>b[j];
FindMid(a,b,n);
cout<<"两个有序序列的中位数为:"<<FindMid(a,b,n)<<endl;
return 0;
}
运行结果: