今天做一道算法题,用到了upper_bound,第一次需要给upper_bound加谓词功能。题中需要比较的是结构体,我就这样调用upper_bound:
/**
* Definition for an interval.
* struct Interval {
* int start;
* int end;
* Interval() : start(0), end(0) {}
* Interval(int s, int e) : start(s), end(e) {}
* };
*/
Interval newInterval(2,3);
auto iter=upper_bound(intervals.begin(),intervals.end(),newInterval,[](auto a,auto b){return a.start<=b.end};);
然后我发现用这个谓词起到了lower_bound的效果。
我主要不是想说这道题,我是突然发现,当lower_bound莫名奇妙不起作用的时候,可以试试把upper_bound的谓词换成<=,它和lower_bound的效果是一样的。下面贴一下VC++里 upper_bound的源码实现:
template<class _FwdIt,
class _Ty,
class _Pr> inline
_FwdIt _Upper_bound_unchecked(_FwdIt _First, _FwdIt _Last,
const _Ty& _Val, _Pr _Pred)
{ // find first element that _Val is before, using _Pred
_Iter_diff_t<_FwdIt> _Count = _STD distance(_First, _Last);
while (0 < _Count)
{ // divide and conquer, find half that contains answer
_Iter_diff_t<_FwdIt> _Count2 = _Count >> 1; // TRANSITION, VSO#433486
const auto _Mid = _STD next(_First, _Count2);
if (_Pred(_Val, *_Mid))
{
_Count = _Count2;
}
else
{ // try top half
_First = _Next_iter(_Mid);
_Count -= _Count2 + 1;
}
}
return (_First);
}
读过源码后是知道了为什么upper_bound把谓词改为<=就可以当upper_bound用了,因为这句话:if (_Pred(_Val, *_Mid)),这里是val在其,mid在后,正常的非模板版本应该是if(nums[mid]>val),所以这里改成<=,就是仅将=的情况划给了upper_bound本该查找的范围,因此就等价于了lower_bound。
但是我还是不明白我直接用lower_bound并且不改谓词,然后又读了一下lower_bound的VC++源码,恍然大悟。
template<class _FwdIt,
class _Ty,
class _Pr> inline
_FwdIt _Lower_bound_unchecked(_FwdIt _First, _FwdIt _Last,
const _Ty& _Val, _Pr _Pred)
{ // find first element not before _Val, using _Pred
_Iter_diff_t<_FwdIt> _Count = _STD distance(_First, _Last);
while (0 < _Count)
{ // divide and conquer, find half that contains answer
_Iter_diff_t<_FwdIt> _Count2 = _Count >> 1; // TRANSITION, VSO#433486
const auto _Mid = _STD next(_First, _Count2);
if (_Pred(*_Mid, _Val))//重点
{ // try top half
_First = _Next_iter(_Mid);
_Count -= _Count2 + 1;
}
else
{
_Count = _Count2;
}
}
return (_First);
}
if (_Pred(*_Mid, _Val))//重点是这句话,lower_bound的谓词参数是mid在前,val在后的,因此给lower_bound添加谓词,得和upper_bound反过来添加,我把题里的语句改成:
auto iter1=lower_bound(intervals.begin(),intervals.end(),newInterval,[](auto b,auto a){return b.end<a.start;});
问题就迎刃而解了。我觉得VC++源码写成这样,确实方便了它自身的实现,但是很不方便用户的调用,毕竟,在没有读过源码的情况下,谁会认为upper_bound和lower_bound的谓词参数顺序是相反的呢?