面试100题:二分查找
Posted 七月在线实验室
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试100题:二分查找相关的知识,希望对你有一定的参考价值。
题目描述
给定一个排好序的数组,查找某个数是否在这个数组中,请编程实现。
分析与解法
一看到数组本身已经有序,直观的反应可能是用二分查找算法,毕竟二分查找算法的适用条件就是要求数组是有序的。那么什么是二分查找呢?
二分查找可以解决已排序数组的查找的问题,即只要数组中包含 T(要查找的值),那么通过不断缩小包含T的数据范围,就可以最终找到要找的数T。其算法流程如下。
(1)一开始,数据范围覆盖整个数组。
(2)将数组的中间项与T进行比较,如果T比数组的中间项小,则到数组的前半部分继续查找,反之,则到数组的后半部分继续查找。
(3)这样,每次查找都可以排除一半元素,相当于范围缩小一半。这样反复比较,反复缩小范围,最终会在数组中找到T,或者确定T不在此数组中。
对于包含n个元素的数组,整个查找过程大约要经过log n次比较。
此时,可能有读者心里想,不就二分查找嘛,太简单了。但是,《编程珠玑》的作者Jon Bentley曾在贝尔实验室做过一个实验,即给一些专业的程序员几个小时的时间,用任何一种语言编写二分查找的程序(写高级伪代码也可以),结果参与编写的一百多个人中,90%的程序员写的程序中有bug(没发现bug的代码不代表就正确)。也就是说,在足够的时间内,只有大约10%的专业程序员可以把二分查找写对。此外,高德纳在《计算机程序设计的艺术 第3卷:排序和查找》的6.2.1节的“历史与参考文献”中指出,虽然早在1946年就有人将二分查找的方法公诸于世,但直到1962年才有人写出没有bug的二分查找程序。
实际上,要想编写出正确的二分查找程序,必须注意到两点:一点是判断循环体是否终止的语句的编写,另外一点是边界值left、right和区间值这三个地方要保持一致。
关于第二点再详细说明一下。比如,如果令right=n−1,则while循环的循环条件为left <= right,从而更新右边界位置的时候为right=middle−1;而如果令right=n,则while循环的循环条件为left < right,从而更新右边界位置的时候为right=middle。同时,middle的计算不能写在while循环外,否则无法得到更新。
以下是一份参考实现:
int BinarySearch(int array[], int n, int value)
{
int left = 0;
int right = n - 1;
// 如果上面这句是int right = n的话,则下面有两处地方需要修改,以保证一一对应:
// 1. 循环的条件是while(left < right);
// 2. 循环内,当array[middle] > value的时候,right = mid。
while (left <= right) // 循环条件,适时而变
{
// 求中间位置,使用移位的方法是为了防止溢出,同时也更高效。注意,每次循环都需要更新
int middle = left + ((right - left) >> 1);
if (array[middle] > value)
{
right = middle - 1; // right赋值,适时而变
}
else if (array[middle] < value)
{
left = middle + 1;
}
else
{
// 可能会有读者认为刚开始时就要判断相等,但其实无关紧要,毕竟数组中不相等的情况更多
return middle;
}
}
return -1;
}
本文摘自July《编程之法:面试和算法心得》第4.1节
以上是关于面试100题:二分查找的主要内容,如果未能解决你的问题,请参考以下文章