二分查找(英语:binary search),也称折半搜索(英语:half-interval search)、对数搜索(英语:logarithmic search),是用来在一个有序数组中查找某一元素的算法。
以在一个升序数组中查找一个数为例。
它每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值同理,只需到左侧查找。
int binary_search(int start ,int end ,int key)
{
int back=-1;//未搜索到返回-1
int mid;
while(start<=mid)
{
mid=start+((end-start)>>1);
if(a[mid]<key)
start=mid+1;
else if(a[mid]>key)
end=mid-1;
else
{// 最后检测相等是因为多数搜索情况不是大于就是小于
back=mid;
break;
}
}
return back;
}
C++ 标准库中实现了查找首个不小于给定值的元素的函数 std::lower_bound 和查找首个大于给定值的元素的函数 std::upper_bound,二者均定义于头文件 <algorithm> 中。二者均采用二分实现,所以调用前必须保证元素有序。
int A[100005]; // 示例全局数组
int lower(const void *p1, const void *p2) {
int *a = (int *)p1;
int *b = (int *)p2;
if ((b == A || compare(a, b - 1) > 0) && compare(a, b) > 0)
return 1;
else if (b != A && compare(a, b - 1) <= 0)
return -1; // 用到地址的减法,因此必须指定元素类型
else
return 0;
}// 查找首个不小于待查元素的元素的地址
int upper(const void *p1, const void *p2) {
int *a = (int *)p1;
int *b = (int *)p2;
if ((b == A || compare(a, b - 1) >= 0) && compare(a, b) >= 0)
return 1;
else if (b != A && compare(a, b - 1) < 0)
return -1; // 用到地址的减法,因此必须指定元素类型
else
return 0;
}// 查找首个大于待查元素的元素的地址
三分法可以用来查找凸函数的最大(小)值。
画一下图能够帮助理解(图待补)
如果 lmid 和 rmid 在最大(小)值的同一侧:由于单调性,一定是二者中较大(小)的那个离最值近一些,较远的那个点对应的区间不可能包含最值,所以可以舍弃。
如果在两侧:由于最值在二者中间,我们舍弃两侧的一个区间后,也不会影响最值,所以可以舍弃。
lmid = left + (right - left >> 1);
rmid = lmid + (right - lmid >> 1); // 对右侧区间取半
if (cal(lmid) > cal(rmid))
right = rmid;
else
left = lmid;