首先,先说明 lower_bound 与 upper_bound 的含义。对于区间 [first,last) 内的元素:
1.lower_bound :寻找最远的 i,使得 [ first, i ) 中的每个迭代器 j 都满足 *j < value
2.upper_bound:寻找最远的 i,使得 [ first, i ) 中的每个迭代器 j 都不满足 *j > value
示例:
序列: 1,2,3,5,6
3 的 lower_bound : 3。3 的 upper_bound : 5
4 的 lower_bound : 5。4 的 upper_bound : 5
实现:
使用二分查找法找到对应的位置,重点是 lower_bound 与 upper_bound 判断之间的区别,lower_bound 要找到第一个不小于 value 的元素,因此将所有小于等于 value 的值划分到左区间;upper_bound 要找到第一个大于 value 的值,因此将所有大于等于 value 的值划分到右区间。注意划分左右区间时,刚好抹去了中间的元素。这是为了避免死循环。具体代码如下:
1.lower_bound:
template<class RandomAccessIterator,class T,class Distance>
RandomAccessIterator __lower_bound(RandomAccessterator first, RandomAccessIterator last, const T& value, Distance*, random_access_iterator_tag)
{
Distance len = _LXX::distance(first, last);
Distance half;
RandomAccessIterator middle;
while (len > 0)
{
half = len >> 1;
middle = first + half;
if (*middle < value) //*middle < value, 所找的值一定在右半部分
{
first = ++middle;
len = len - half - 1;
}
else //*middle >= value, 所找的值在左半部分或者在 middle 处
len = half; //此处若是写为 len = half + 1, 则当 value == middle, len = 0 时将进入死循环
}
return first;
}
*注意二分区间的划分:左区间:len = half,右区间:len = len - half - 1 ,(half = len >> 1),其中左右区间划分不包含中间元素(len_left + len_right = len - 1),但是当 中间元素 == value 时,左区间中若还有 value,则忽略中间元素不会影响结果;若左区间中无 value,则二分查找会找回到中间元素的前一个元素,又因为前一个元素小于中间元素,则会更新 first = ++middle,即返回超出区间的下一个元素(左区间的下一个元素即是中间元素)。因此,忽略中间元素仍然能找回来。
2.upper_bound:
template<class RandomAccessIterator, class T, class Distance>
RandomAccessIterator __upper_bound(RandomAccessIterator first, RandomAccessIterator last, const T &value, Distance *,random_access_iterator_tag)
{
Distance len = _LXX::distance(first, last);
RandomAccessIterator middle;
Distance half = 0;
while (len > 0)
{
half = len >> 1;
middle = first + half;
if (value < *middle)
{
len = half;
}
else
{
first = middle + 1;
len = len - half - 1;
}
}
return first;
}