C++ STL 二分查找 lower_bound, upper_bound和equal_range底层实现分析
函数功能总结
在复习时学到STL的二分查找算法,基本上是四个:lower_bound,upper_bound,equal_range和binary_search,四个函数的基本功能如下所示:
函数名 | 功能 |
---|---|
lower_bound( begin,end,num) | 要求数组从小到大非递减排序,从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。 |
upper_bound( begin,end,num) | 要求数组从小到大非递减排序,从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。 |
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp); | 在 [first, last) 区域内查找第一个大于val的元素,并且比较函数自定义 |
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp); | 查找[first, last)区域中第一个大于val的元素,并且比较函数自定义 |
pair<ForwardIterator,ForwardIterator> equal_range (ForwardIterator first, ForwardIterator last, const T& val); | 找到 [first, last) 范围中所有等于 val 的元素。对于equal_range函数,当查找成功时:第 1 个迭代器指向的是 [first, last) 区域中第一个等于 val 的元素;第 2 个迭代器指向的是 [first, last) 区域中第一个大于 val 的元素。反之如果查找失败,则这 2 个迭代器要么都指向大于 val 的第一个元素(如果有),要么都和 last 迭代器指向相同 |
pair<ForwardIterator,ForwardIterator> equal_range (ForwardIterator first, ForwardIterator last, const T& val, Compare comp); | 根据 comp 指定的规则,找到 [first, last) 范围内所有满足比较函数且等于val 的元素 |
bool binary_search (ForwardIterator first, ForwardIterator last, const T& val); | 查找 [first, last) 区域内是否包含 val |
bool binary_search (ForwardIterator first, ForwardIterator last, const T& val, Compare comp) | 根据 comp 指定的规则,查找 [first, last) 区域内是否包含 val |
为什么写这篇文章
在学习过程中我想要从底层实现看懂每个查找算法的执行过程,看到equal_range其实是调用lower_bound和upper_bound两个模板函数后,对参考材料 1:C++ lower_bound() upper_bound() 函数用法详解(深入了解,一文学会)文中一句话产生了疑惑:
所以经过代码一步步测试后明确了底层实现,下面来一步步阐述。
先总结答案
- 在lower_bound的自定义比较函数中,val作为第一个实参传入;而upper_bound将val作为第一个实参传入。
- equal_range的底层实现基于lower_bound和upper_bound两个函数,并且upper_bound函数的开始迭代器first 来自 lower_bound返回的迭代器。
lower_bound的底层实现
lower_bound() 函数定义在头文件中,其语法格式有 2 种,分别为:
//在 [first, last) 区域内查找不小于 val 的元素
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
const T& val);
//在 [first, last) 区域内查找第一个不符合 comp 规则的元素
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last,
const T& val, Compare comp);
其中,first 和 last 都为正向迭代器,[first, last) 用于指定函数的查找范围;val 用于指定目标元素;comp 用于自定义比较规则,此参数可以接收一个包含 2 个形参(第二个形参值始终为 val)且返回值为 bool 类型的函数,可以是普通函数,也可以是函数对象。
lower_bound的底层实现代码可以在<stl_algo.h>头文件找到
易理解的底层实现如下所示。
可以看出默认比较方法为迭代器指向对象小于目标元素*it<val
时开始位置后移到比较元素下一位,而不满足该条件时结束位置前移到比较元素;而自定义比较函数则是将判断条件改为comp(*it,val)
template <class ForwardIterator, class T>
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator it;
iterator_traits<ForwardIterator>::difference_type count, step;
count = distance(first,last);
while (count>0)
{
it = first; step=count/2; advance (it,step);
if (*it<val) {
//对应第 1 种语法格式
first=++it;
count-=step+1;
}
else count=step;
}
return first;
}
template <class ForwardIterator, class T, class Compare>
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& val, Compare comp)
{
ForwardIterator it;
iterator_traits<ForwardIterator>::difference_type count, step;
count = distance