【数据结构与算法】——二分查找

二分查找有着查找速度快,平均性能好的优点,但要建立在要查找的数据必须时有序的。

今天我们今天来学习二分查找算法。

有天A和B同时去一家公司面试,只面试管在纸上写下一行数,如:

1,3,5,8,10,15,20。

问:你们谁能用程序在最短的时间找出15?
B:只需要从第一个元素开始往后依次比较,比较六次就可以找到了。

这时A回答:我只需要两次就可以找到。
面试官:A你能说说如何做吗?
A:你给的数字是有序的,所以没有必要一个一个比较,可以逐渐缩小要查找的范围来查找,我们可以先看中间的元素,如果是15,就直接找到了,如果15比中间的元素大,那就应该去中间元素的右边去找,反之,在左边找。
A说完后立即画了个图。

A:我们可以用数组arr去存储这些元素用Left和Right两个变量划定查找的区间,第一次比较15大于中间元素8,那么下一次查找就是在8的下一个位置到20的区间去查找。

 

 

这时面试官又问:如果是查找12呢?这个数字不存在我们又该如何完成?
A:如果查找12,同样的思路,第一次查找和15一样,第二次找12小于15,应该去15的左边,8的右边去查找。


 

当Left和Right指向同一个位置时也就是只剩下一个元素,但是还是不相等,就是找不到了,也就是数据中没有12这个元素。

二分查找代码的实现
面试官在肯定了A的思路后问:那你能写出这个程序的代码吗?

不一会A给出了代码

int binarySrarch(int arr[], int key,int arrlen)
{
	int Letf = 0;
	int Right = arrlen - 1;
	int mid;
	while (Letf <= Right)
	{
		mid = (Letf + Right) / 2;//查找区间的中间位置
		if (arr[mid] > key)
		{
			Right = mid - 1;
		}
		else if(arr[mid]<key)
		{
			Letf = mid + 1;
		}
		else
		{
			return mid;
		}

	}
	return -1;//没有找到
}


这是B插话问:这个判断循环条件能不能改为Left<Right呢?
A:不行,如果改为Left<Right,就有可能出现来数据中有待查数据却找不到的情况,比如查10、经过两次查找后,Left和Right都指向元素10但此时wile(low<high)不成立. 不进入循环避而找不到。


面式官在看完代码后问A:你觉得你的代码有什么问题吗?

A在看了代码后检查不出什么!尴尬的笑了笑说看不出!
面试官:你看mid=(Left+Right)/2,这行代码,Left和Right都是整形,当我们要 在一个很大的数据量中查找时,这时的Left和Right就会很大,lLeft+Right就容易产生溢出,结果就应为负数那么mid=(Left+Right)/2也就为负数了,程序就错了。

这时AB同问:那如何解决?
面试官:给你两个容量相同的杯子,杯子里都装了半杯以上的水,你怎样才能将两杯水变得体积相同?
你的代码(Left+Right)/2就相当于把一个杯子的水倒入另一个杯子中然后再均分,这样会使水流出。正确的做法是将两杯水中体积大减去体积小的等于水的体积差值,再将这个差值的一半倒入水少的杯子中就行了。也就是mid= Left+(Right - Left)/2。


 

int binarySrarch(int arr[], int key,int arrlen)
{
	int Letf = 0;
	int Right = arrlen - 1;
	int mid;
	while (Letf <= Right)
	{
		mid = Left+(Right -Left) / 2;//查找区间的中间位置
		if (arr[mid] > key)
		{
			Right = mid - 1;
		}
		else if(arr[mid]<key)
		{
			Letf = mid + 1;
		}
		else
		{
			return mid;
		}

	}
	return -1;//没有找到
}

二分查找的时间复杂度


在使用二分查找时,如果要查找的数据规模为n,二分查找一次后规模就变成了N/2,二分查找两次后的规模为n/2^2,二分查找m次后规模变成了n/2^m。

最坏情况,数据中没有该值
假设,当二分查找后剩下一个元素,那么此时规模为1,此时已经二分查找了m次,也就是n/2^m=1 m=lg(n)。再循环一次也不到,跳出循环,所以说最多循环m+1次,故二分查找的最坏是间复杂度为O(n)=lg(n)。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值