二分查找算法
复杂度
log
2
N
\log_2N
log2N
二分查找的前提是待查找的序列必须是有序的。另外一点,C++中的序列都是前闭后开的。如果使用STL,默认是递增顺序,递减的顺序需要自定义比较函数。二分查找可以自己实现或者使用STL的std::binary_search()
实现,后者只能给出需要查找的元素是否在某序列中,返回bool
值。然而,当我们需要知道元素的具体位置时,需要自己写一个二分查找算法。一下给出了两种方式,注意自定义函数的区间调整。
如果一个容器是有序的,而且元素可以使用==
运算符进行比较,那么完全可以使用库函数lower_bound()
执行二分查找,函数返回第一个大于等于目标元素的位置,如果所有元素都小于目标元素的迭代器,则返回尾后替代器;同时注意upper_bound()
函数,该函数也是执行二分查找,不过是返回第一个大于目标元素的迭代器。利用upper_bound
和lower_bound
之差可以记录相等元素的个数。。
不过,我们要自己掌握这种算法,自己写这种算法时,与STL的区别在于右侧也是闭区间,这样比较好记,而且容易寻找下标的规律。算法终止条件的核心是下界大于上界。下面给出代码:
#include <iostream>
#include <vector>
using namespace std;
template<typename T>
int BinSearch(vector<T>vec, T key) {
if(vec.empty()) {
return -1;
}
int low = 0, high = vec.size() - 1;
while(low <= high) {
int mid = low + (high - low) / 2;
if(vec[mid] == key) {
return mid;
} else if(vec[mid] > key) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
int main() {
return 0;
}
二分查找下标的规律总结:
- 如果可以找到目标,分为两种情况,这两种情况对于子区间同样适用:
- 区间的两侧是目标: l o w = h i g h = m i d low=high=mid low=high=mid
- 恰好是 m i d = l o w + ( l o w + h i g h ) / 2 mid=low+(low+high)/2 mid=low+(low+high)/2,此时三者都不变
- 如果找不到目标,则 l o w = h i g h + 1 low=high+1 low=high+1,此时的 m i d mid mid等于 l o w low low或者 h i g h high high,由具体的运算情景决定
- 如果 h i g h = l o w + 1 high=low+1 high=low+1时,在这里先不论是否有目标值,此时一定有: m i d = l o w mid=low mid=low。假设我们此时还没找到元素,那么如果目标值小于 m i d mid mid指示值,则 h i g h high high移动向 l o w low low;否则 l o w low low移动向 h i g h high high;最终 m i d = h i g h = l o w mid=high=low mid=high=low。