赞
踩
二分查找也称为折半查找(binary search)
,适用于顺序存储结构的线性表
,且表中元素是有序排列
的情况。对于一个顺序排列的数组而言,当查找区间有不止一个元素的时候
(即左边界不超过右边界),每次循环取当前区间中间的元素与目标值比较,根据以下三种比较结果判断跳出循环或更新左右边界:
由于二分查找的适用场景为顺序表,因此空间复杂度为
O
(
1
)
O(1)
O(1)。
假设数组中有n个元素,且为顺序排列,如果进行进行二分查找过程如下:
由此可见,若在最坏情况
下经过x次查找寻找到答案,最终区间长度应为1,即:
n
/
2
x
−
1
=
1
n / 2^{x - 1} = 1
n/2x−1=1
x
=
l
o
g
2
n
x = log_2n
x=log2n因此,二分查找的时间复杂度为
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)。
假设一个已经排好序的数组num中有n个元素,t为需要查找的目标值。
int binary_search(int t) {
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (num[mid] == x) {
return 1;
} else if (x > num[mid]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
return 0;
}
在缩减查找区间
的时候,需要注意的是,每次都略过了mid这个中间元素。这是因为在前面的判断中已经确定了num[mid]不是我们需要的值,所以在下一次循环查找中,不需要将其包含在查找区间中。
在实际的问题中,有时二分的对象未必是答案,而是需要将二分的对象经过某些特殊运算得到的值进行判断,由此得到满足条件的解。此类型问题的答案通常具有单调性
,且多数为边界值解(如求最大的最小值等),这类问题被统称为二分答案问题
。
对于二分答案类型问题的思路,可以从二分的对象入手进行推导:
代码模型
,根据不同输入样例求解。因此,二分答案的结果可以近似为两种类型:00001111型和11110000型。
两种类型的代码模版如下:
00001111型
while (l != r) {
int mid = (l + r) / 2;
if (func(mid) >= t) { // t为目标查找数
r = mid;
} else {
l = mid + 1;
}
}
return r; // return l;
注意:
需要
包含mid。不需要
包含mid。11110000型
while (l != r) {
int mid = (l + r + 1) / 2;
if (func(mid) <= t) { // t为目标查找数
l = mid;
} else {
r = mid - 1;
}
}
return l; // return r;
注意:
死循环
。所以需要使用
m
i
d
=
(
l
+
r
+
1
)
/
2
mid = (l + r + 1) / 2
mid=(l+r+1)/2向上取整来计算mid的值。需要
包含mid。不需要
包含mid。对于小数二分,推导思路与上述两种问题一样,唯一需要注意的地方是循环的条件发生了变化。因为二分的对象为浮点型数据
,查找区间应为开区间
而不是闭区间了,所以不需要再判断左右边界是否相等,而是通过判断左右边界之间差值的精度(如r - l > 0.00001),近似的判断左右边界是否重合。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。