lower_bound()源码解析

lower_bound() 可以通过二分法在数组里查找满足条件的某个数,它默认查找的是数组中第一个大于等于 val 的数。

如下面的这段代码将会输出 3;

vector<int> arr={1,3,5,7};
cout << *lower_bound(arr.begin(), arr.end(), 3); // 打印3

还有一个 upper_bound() 函数与 lower_bound() 很相似,但是它默认返回的是数组中第一个大于 val 的数。

自然而然的想到,能否利用这两个函数进一步找到数组中最后一个小于等于 val 的数,以及最后一个小于 val 的数。

为此我们对 lower_bound() 的源码稍作分析。

首先,lower_bound() 会调用更底层的一个函数 __lower_bound()lower_bound() 默认的比较函数是 __iter_less_val(),即迭代器的值小于 val 时返回 true,我们也可以自己定义比较函数 __comp(iter, val)

    lower_bound(_ForwardIterator __first, _ForwardIterator __last,
		const _Tp& __val, _Compare __comp)
    {
      return std::__lower_bound(__first, __last, __val,
				__gnu_cxx::__ops::__iter_comp_val(__comp));
    }

__lower_bound() 里, 使用二分法进行查找,以默认的比较函数 __iter_less_val 为例进行说明

  • 如果 *__middle < __val ,(即 __comp(__middle,val) 为 true),左边界向右边收缩
  • 如果 *__middle >=__val, (即 __comp(__middle,val) 为 false)右边界向左边收缩

由于最后返回的是左边界的迭代器,左边的迭代器总是满足条件 2,而不满足条件 1

所以总体上看,lower_bound() 的效果在于,不断的向左收缩右边界,找到一个大于等于 val 的值

如果把默认的比较函数换成一般的函数 __comp(iter,val),那么 lower_bound() 相当于找到第一个 !comp(iter, val) 的值。

upper_bound() 默认的比较函数是 __val_less_iter(),也可以自定义比较函数 __comp(val,iter),它和 lower_bound 的区别主要在于这里的 val 是第一参数。

upper_bound() 返回第一个满足 __comp(val, iter) 的数,如使用默认的仿函数,将返回第一个满足 val< *iter 的数。

分析到这里,回到我们的问题,怎么找到数组中最后一个小于等于 val 的数,以及最后一个小于 val 的数?

注意到不管是 lower_bound() 还是 upper_bound(), 它们在满足了条件还是会不断从右向左收缩边界,最终返回左边界的值,对于 lower_bound() 来说,这个条件是 !comp(iter,val),而对于 upper_bound() 来说,这个条件是 comp(val, iter)

而要找到最后一个小于等于 val 的数,或者最后一个小于 val 的数,显然需要我们在满足小于等于条件时不断从左向右收缩边界,最终返回右边界的值。

为了做到这一点,可以使用 reverse_iterator!

剩下的就是把小于等于 val 的条件变换成 !__comp(iter,val),看下面的变换方式

*iter<=val <====> !(iter>val) <=====> !greater(iter,val) <====> !greater<int>()

也就是说只要使用greater<int>()作为比较函数就可以实现查找数组里最后一个小于等于 val 的数

同理 upper_bound() 搭配 reverse_iterator 和 greater<int>() 能够实现在递增数组里查找最后一个小于 val 的值

最后是一个小测试

int main(){
    vector<int> arr = {1,3,5,7,9,11,13,15};
    cout << *lower_bound(arr.rbegin(), arr.rend(), 9, greater<int>()).<< endl; // 返回9
    cout << *upper_bound(arr.rbegin(), arr.rend(), 9, greater<int>()) << endl; // 返回7
    for(auto arr_it = arr.rbegin(); arr_it != arr.rend(); arr_it++){
        cout << *arr_it << " ";
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值