二分查找(示例 C++)

二分查找

引例:A心里想一个1-1000之间的数,B来猜,可以问问题,A只能回答是或否。怎么猜才能问的问题次数最少?

  1. 顺序查找:是1吗?是2吗? …是999吗?平 均要问500次
  2. 二分查找:大于500吗?大于750吗?大于625吗? … 每次缩小猜 测范围到上次的一半,只需要10次
  3. 二分查找的内容必须是有序的。

例1:写一个函数BinarySeach,在包含size个元素的、从小到大排序的int数组a里查找元素p,如果找到,则返回元素下标,如果找不到,则返回-1。要求复杂度O(log(n))。

代码:

int BinarySeach(int a[],int size,int p){
    
    
	int L = 0;	//查找区间的左端点
	int R = size - 1;	//查找区间的右端点
	while(L <= R){
    
    	//如果查找区间不为空就继续查找 
		int mid = L+(R-L)/2;	//取查找区间正中元素的下标 
		if(p == a[mid])
			return mid;
		else if(p > a[mid])	//说明p在a[]的左半部 
			L = mid + 1;	//重置查找区间的左端点 
		else 
			R = mid - 1;	// 重置查找区间的右端点
	}
	return -1;
}	

例2:写一个函数LowerBound,在包含size个元素的、从小到大排序的int数组a里查找比给定整数p小的,下标最大的元素。找到则返回其下标,找不到则返回-1。

代码:

int LowerBound(int a[],int size,int p){
    
    
	int L = 0;	//查找区间的左端点 
	int R = size - 1;	//查找区间的右端点 
	int lastPos = -1;	//目前为止找到的最优解 
	while(L <= R){
    
    	//如果查找区间正中元素的下标
		int mid = L+(R-L)/2;	//去查找区间正中元素的下标
		if (a[mid] >= p)
			R = mid - 1;
		else{
    
    
			lastPos = mid;
			L = mid+1;
		}
	}
	return lastPos;
}

注意:
int mid = (L+R)/2; //取查找区间正中元素的下标
为了防止(L+R)过大溢出:
int mid = L+(R-L) /2;


例3:二分法求方程的根
求下面方程的一个根:f(x)= x3-5x2+10x-80 = 0; 若求出的根是a,则要求|f(a)|<= 10-6

解法: 对f(x)求导,得f’(x)=3x2-10x+10。 由一元二次方程求根公式知方程f’ (x)= 0无解,因此f’(x)恒大于0。故f(x)是单调递增的。易知f(0) < 0且f(100)>0,所以区间[0, 100]内必然有且只有一个根。由于f(x) 在[0, 100]内是单调的,所以可以用二分的办法在区间[0, 100]中寻找根。

代码

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;

double EPS = 1e-6;
double f(double x){
    
    
	return x*x*x - 5*x*x + 10*x - 80; 
}
int main(){
    
    
	double root, x1 = 0,x2 = 100,y;
	root = x1+(x2-x1)/2;
	int triedTimes = 1;//记录一共尝试多少次
	y = f(root);

	while( fabs(y) > EPS){
    
    
		if(y > 0)
			x2 = root;
		else 
			x1 = root;
		root = x1+(x2-x1)/2;
		y = f(root);
		triedTimes++;
	}
	printf("%.08f\n",root);
	printf("%d",triedTimes);
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_44524918/article/details/108856751