基础二分法及其拓展应用

一、二分法

二分法应用于具有单调性的一组数据的查找中,能够将复杂度由O(N)降低到O(logN),实现方式简单,通过对比目标数组下表为mid处数值与查找值之间的大小关系以不断更新[left,right]的值,最终找到目标数。其中也包含着二叉树的思想,是不错的查找算法。

二分法可以使用递归实现,但在程序设计时更多采用非递归方式

tip:如果二分上界超过int型数据范围的一半,那么当欲查询元素在序列靠后的位置时可能会导致
mid=(left+right)/2这条语句溢出,因此考虑使用mid = left + (right-left)/2来替代

二、实现方式

# include<cstdio>

//假设A[]单调递增
int binarySearch(int A[], int left, int right, int x){
	int mid;
	while(left <= right)
	{
		mid = (left+right)/2;
		if(A[mid]==x)
			return mid;
		else if(A[mid]>x)
			right = mid-1;
		else
			left = mid+1;
	}
	return -1;
}

注意left<=right中的等于,因为倘若没有这个等于会漏掉一种情况下数据的对比,即mid== left == right的情况下A[mid]是否等于x。

三、问题拓展

1.2都是建立在单增条件下的查找

1.返回第一个大于等于x的元素位置

如果mid>=x,则直接返回
如果mid<x, 则将left增加为mid+1

# include<cstdio>

//假设A[]单调递增
int binarySearch(int A[], int left, int right, int x){
	int mid;
	if(A[right]<x) //假设最大的都小于x,说明找不到
		return -1;
	while(left < right)
	{
		mid = (left+right)/2;
		if(A[mid]>=x)
			right = mid;//往[left,mid]里寻找
		else
			left = mid+1;//往[mid+1,right]里寻找
	}
	return left;
}

2.返回第一个大于x的元素位置

int binarySearch(int A[], int left, int right, int x){
	int mid;
	if(A[right]<x) //假设最大的都小于x,说明找不到
		return -1;
	while(left < right)
	{
		mid = (left+right)/2;
		if(A[mid]>x)//往[left,mid]寻找
			right = mid;
		else 
			left = mid+1;//往[mid+1,right]寻找
	}
	return left;
}

进而我们能够推导出求返回特定元素的位置。

3.根号2近似值的计算

进一步对于任何单调函数我们都能够通过二分法逼近这个值。(三次根号,对数函数等等)

# include<cstdio>
# include<algorithm>
using namespace std;

const double eps = 1e-6;
double f(double x){
	return x*x;
}

int main()
{
	double mid,left=0,right=2;
	while((right-left)>eps){
		mid = (left+right)/2;
		if(f(mid)>2)
			right = mid;
		else
			left = mid;
	}
	printf("%lf",mid);
}

4.装水问题(方程解的逼近)

在这里插入图片描述

一侧面为半圆的储水装置,该半圆的半径为R,要求往里面装入高位h的水,使其侧面看去的面积S1与半圆面积S2比例恰好为r,如上图所示,现给定R和r,求高度h。
显然,当h增大时,r一定增大,这是一个单调增的函数,满足使用二分法。

# include<cstdio>
# include<algorithm>
# include<cmath>
const double pi = acos(-1.0); //PI
const double eps = 1e-5; //精度到1e-5
using namespace std;

double area(double height, double R)
{
	double alpha = 2*acos((R-height)/R);
	return alpha*R*R/2;
}

double height(double R, double ratio)
{
	double S2 = pi*R*R/2, S1 = S2*ratio,left = 0,right = R,mid;
	while(right-left>eps){
		mid = (right+left)/2;
		if(area(mid,R)>S1)
			right = mid;
		else
			left = mid;
	}
	return mid;
}

int main()
{
	double h = height(5.2,0.5);
	printf("%lf",h);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值