“二分查找”——Jon Bentley:90%以上的程序员无法正确无误的写出

本文深入讲解了二分查找算法的实现细节,包括如何避免溢出、正确更新中间值及查找范围,展示了完整的C++代码示例,并解释了二分查找适用场景及注意事项。

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

#include<iostream> 
#include<iomanip>  
void print(int i,int j,int a[]);
int find(int a[],int n,int k);

int find(int a[],int n,int k)
{
	int high=n-1,low=0,mid;//初始化,注意n为数组长度
	while (low<=high)
	{
		//mid=(low+high)/2;当n较大时(low+high)会溢出,应将式子等价代换成下面的式子
		mid=low+(high-low)/2;//或mid=low+(high-low)>>1

		std::cout<<"low="<<low<<"  high="<<high;
		std::cout<<"  (low+high)/2="<<std::setiosflags(std::ios::fixed)<<std::setw(4)<<std::setprecision(1);
		std::cout<<(low*1.0+high)/2<<"  mid="<<mid<<"  a["<<mid<<"]="<<a[mid]<<std::endl<<std::endl;
		//显示程序中间变量,理清程序过程。(low*1.0+high)/2是为了输出mid的小数值

		if(k==a[mid])
			return mid;
		else if(k<a[mid])
		{
			high=mid-1;
			print(low,high,a); //显示程序中间变量,理清程序过程
		}
		else
		{
			low=mid+1;
			print(low,high,a); //显示程序中间变量,理清程序过程
		}
	}
	return -1;
}

void print(int i,int j,int a[])//输出
{
	while(i<=j)
	{
		std::cout<<a[i]<<"   ";
		i++;
	}
	std::cout<<std::endl;
}


int main()
{
	int a[]={10,11,12,13,14,15,16,17,18,19};
	print(0,9,a);
	std::cout<<"k所在数组下标"<<find(a,10,15)<<std::endl;
	return 0;
}

 1>二分查找可以解决(预排序数组的查找)问题:只要数组中包含T(即要查找的值),那么通过不断缩小包含T的范围,最终就可以找到它。一开始,范围覆盖整个数组。将数组的中间项与T进行比较,可以排除一半元素,范围缩小一半。就这样反复比较,反复缩小范围,最终就会在数组中找到T,或者确定原以为T所在的范围实际为空。对于包含N个元素表,整个查找过程大约要经过log(2)N次比较。

2>代码中要注意的地方是:

(1)语句 mid=low+(high-low)/2 要放入while循环中实现对mid的更新

(2)while循环的终止条件是low<=high而不是low<high因为当区间只有一个元素时low==high==mid,如果少了=号,此情况下的最后一次循环丢  失,在VC2005下运行上述程序就将令 k=13,可以看到运行结果的倒数第三行显示" low=3  high=3  (low+high)/2=3  mid=3  a[3]=13 "即为此种情况

(3) 语句mid=(low+high)/2是容易忽略的一个bug,即当n值较大时lowhigh的大小都很容易就可能接近n,这时溢出造成mid为负值,数组越界

(4)查找范围的缩小是由语句high=mid-1;和low=mid+1;实现的

3>唯一可能还有疑惑的是,在范围的缩小过程中为什么不会遗漏,其实这一点不用怀疑。从程序while循环的框架中我们可以知道,程序执行流程可能有三个去向(1)k==a[mid];(2) k<a[mid];  (3)k>a[mid]; 因为数组a[]是升序的,所以在每一次while循环体执行时,k都会落入相应区域内,而不必要确保mid是否恰好为下标正中间值,即不需要关心左右区域的大小是否相同,查找过程不可能遗漏,也不可能重复。最终要查找的值被找到的时候,一定是k==a[mid],只是k==a[mid]可能是在两种情况下产生的(1)  low<high;       (2)low==high;  在VC2005下运行上述程序,分别令k=15和k=13,则对应这两种情况。

对数组中有重复值的情况的考虑:二分查找主要用于对已排序的无重复的数组的查找,当某些特殊情况下,数组中的值有重复使用二分查找时,所找到的只是其中一个目标值的位置。但我们可以知道其余值在其左右,只需在其左右逐个搜索直到不等于目标值即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值