STL lower_bound upper_bound binary-search

STL中的二分查找——lower_bound 、upper_bound 、binary_search

二分查找很简单,原理就不说了。STL中关于二分查找的函数有三个lower_bound 、upper_bound 、binary_search 。这三个函数都运用于有序区间(当然这也是运用二分查找的前提)。

其中如果寻找的value存在,那么lower_bound返回一个迭代器指向其中第一个这个元素。upper_bound返回一个迭代器指向其中最后一个这个元素的下一个位置(明确点说就是返回在不破坏顺序的情况下,可插入value的最后一个位置)。如果寻找的value不存在,那么lower_bound和upper_bound都返回“假设这样的元素存在时应该出现的位置”。要指出的是lower_bound和upper_bound在源码中只是变换了if—else语句判定条件的顺序,就产生了最终迭代器位置不同的效果。

binary_search试图在已排序的[first,last)中寻找元素value,若存在就返回true,若不存在则返回false。返回单纯的布尔值也许不能满足需求,而lower_bound、upper_bound能提供额外的信息。事实上由源码可知binary_search便是利用lower_bound求出元素应该出现的位置,然后再比较该位置   的值与value的值。该函数有两个版本一个是operator< ,另外一个是利用仿函数comp进行比较。

具体分析见源码:

 //这是forward版本
template <class ForwardIterator, class T>
inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
const T& value) {
return __lower_bound(first, last, value, distance_type(first),
iterator_category(first));
} // 这是版本一的 forward_iterator 版本
template <class ForwardIterator, class T, class Distance>
ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
const T& value, Distance*,
forward_iterator_tag) {
Distance len = ;
distance(first, last, len); // 求取整个范围的长度,ForwardIterator没有-n操作
Distance half;
ForwardIterator middle; while (len > ) { //为了跳出循环,而定义了len,如果用while(true) 然后每次判定长度在break,也行,不过没这个好
half = len >> ; // 除以2,注意这种移位写法,不需编译器进行优化
middle = first; // 这两行令middle 指向中间位置
advance(middle, half); //ForwardIterator没有+n的操作
if (*middle < value) { // 如果中间位置的元素值 < 标的值,value在后半区间
first = middle; // 这两行令 first 指向 middle 的下一位置
++first;
len = len - half - ; // 修正 len,回头测试循环条件
}
else // 注意如果是相等的话,那么执行的是else语句,在前半部分找
// 与opper_bound进行比较
len = half; // 修正 len,回头测试循环条件
}
return first;
}
// 这是带comp反函数的 forward_iterator 版本
template <class ForwardIterator, class T, class Compare, class Distance>
ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
const T& value, Compare comp, Distance*,
forward_iterator_tag) {
Distance len = ;
distance(first, last, len);
Distance half;
ForwardIterator middle; while (len > ) {
half = len >> ;
middle = first;
advance(middle, half);
if (comp(*middle, value)) {
first = middle;
++first;
len = len - half - ;
}
else
len = half;
}
return first;
} // 这是random_access_iterator版本
template <class ForwardIterator, class T, class Compare>
inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
const T& value, Compare comp) {
return __lower_bound(first, last, value, comp, distance_type(first),
iterator_category(first));
} // 这是版本一的 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Distance>
RandomAccessIterator __lower_bound(RandomAccessIterator first,
RandomAccessIterator last, const T& value,
Distance*, random_access_iterator_tag) {
Distance len = last - first; //求取整个范围的长度,与ForwarIterator版本进行比较
Distance half;
RandomAccessIterator middle; while (len > ) {
half = len >> ;
middle = first + half;
if (*middle < value) {
first = middle + ;
len = len - half - ; //修正 len,回头测试循环条件,RamdonAccessIterator版本
}
else
len = half;
}
return first;
} //这是带comp仿函数 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Compare, class Distance>
RandomAccessIterator __lower_bound(RandomAccessIterator first,
RandomAccessIterator last,
const T& value, Compare comp, Distance*,
random_access_iterator_tag) {
Distance len = last - first;
Distance half;
RandomAccessIterator middle; while (len > ) {
half = len >> ;
middle = first + half;
if (comp(*middle, value)) {
first = middle + ;
len = len - half - ;
}
else
len = half;
}
return first;
} // 这是forward_iterator版本
template <class ForwardIterator, class T>
inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
const T& value) {
return __upper_bound(first, last, value, distance_type(first),
iterator_category(first));
} // 这是版本一的 forward_iterator 版本
template <class ForwardIterator, class T, class Distance>
ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
const T& value, Distance*,
forward_iterator_tag) {
Distance len = ;
distance(first, last, len);
Distance half;
ForwardIterator middle; while (len > ) {
half = len >> ;
middle = first;
advance(middle, half);
if (value < *middle) // 如果中间位置的元素值大于标的值,证明在前半部分
len = half; // 修正len
else { // 注意如果元素值相等的话,那么是在后半部分找
// 与lower_bound进行比较
first = middle; // 在下半部分,令first指向middle的下一个位置
++first;
len = len - half - ; // 修正 len
}
}
return first;
} // 这是版本一的 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Distance>
RandomAccessIterator __upper_bound(RandomAccessIterator first,
RandomAccessIterator last, const T& value,
Distance*, random_access_iterator_tag) {
Distance len = last - first;
Distance half;
RandomAccessIterator middle; while (len > ) {
half = len >> ;
middle = first + half;
if (value < *middle)
len = half;
else {
first = middle + ;
len = len - half - ;
}
}
return first;
} // 这是带comp的版本
template <class ForwardIterator, class T, class Compare>
inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
const T& value, Compare comp) {
return __upper_bound(first, last, value, comp, distance_type(first),
iterator_category(first));
} // 这是带comp的 forward_iterator 版本
template <class ForwardIterator, class T, class Compare, class Distance>
ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
const T& value, Compare comp, Distance*,
forward_iterator_tag) {
Distance len = ;
distance(first, last, len);
Distance half;
ForwardIterator middle; while (len > ) {
half = len >> ;
middle = first;
advance(middle, half);
if (comp(value, *middle))
len = half;
else {
first = middle;
++first;
len = len - half - ;
}
}
return first;
} // 这是带comp的 random_access_iterator 版本
template <class RandomAccessIterator, class T, class Compare, class Distance>
RandomAccessIterator __upper_bound(RandomAccessIterator first,
RandomAccessIterator last,
const T& value, Compare comp, Distance*,
random_access_iterator_tag) {
Distance len = last - first;
Distance half;
RandomAccessIterator middle; while (len > ) {
half = len >> ;
middle = first + half;
if (comp(value, *middle))
len = half;
else {
first = middle + ;
len = len - half - ;
}
}
return first;
} // 版本一
template <class ForwardIterator, class T>
bool binary_search(ForwardIterator first, ForwardIterator last,
const T& value) {
ForwardIterator i = lower_bound(first, last, value);
//这里的实现就是调用的lower_bound ,并且如果元素不存在那么lower_bound指向的元素一定是
//operator < 为ture的地方。
return i != last && !(value < *i);
} // 版本二
template <class ForwardIterator, class T, class Compare>
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value,
Compare comp) {
ForwardIterator i = lower_bound(first, last, value, comp);
return i != last && !comp(value, *i);
}

函数lower_bound(first , last , val)在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置

举例如下:

一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标

pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。

pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。

pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。

所以,要记住:函数lower_bound(first , last , val)在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~

返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置

测试代码如下:

 #include <iostream>
#include <algorithm>
#include <functional>
#include <vector> using namespace std; int main()
{
const int VECTOR_SIZE = ; // Define a template class vector of int
typedef vector<int > IntVector ; //Define an iterator for template class vector of strings
typedef IntVector::iterator IntVectorIt ; IntVector Numbers(VECTOR_SIZE) ; IntVectorIt start, end, it, location ; // Initialize vector Numbers
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ; start = Numbers.begin() ; // location of first
// element of Numbers end = Numbers.end() ; // one past the location
// last element of Numbers // print content of Numbers
cout << "Numbers { " ;
for(it = start; it != end; it++)
cout << *it << " " ;
cout << " }\n" << endl ; // return the first location at which 10 can be inserted
// in Numbers
location = lower_bound(start, end, ) ; cout << "First location element 10 can be inserted in Numbers is: "
<< location - start<< endl ;
}

函数upper_bound(first , last , val)返回的在前闭后开区间查找的关键字的上界,如一个数组number序列1,2,2,4.upper_bound(2)后,返回的位置是3(下标)也就是4所在的位置,同样,如果插入元素大于数组中全部元素,返回的是last。(注意:此时数组下标越界!!)

返回查找元素的最后一个可安插位置,也就是“元素值>查找值”的第一个元素的位置

测试代码如下:

 #include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std; void main()
{
const int VECTOR_SIZE = ; // Define a template class vector of int
typedef vector<int, allocator<int> > IntVector ; //Define an iterator for template class vector of strings
typedef IntVector::iterator IntVectorIt ; IntVector Numbers(VECTOR_SIZE) ; IntVectorIt start, end, it, location, location1; // Initialize vector Numbers
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ;
Numbers[] = ; start = Numbers.begin() ; // location of first
// element of Numbers end = Numbers.end() ; // one past the location
// last element of Numbers // print content of Numbers
cout << "Numbers { " ;
for(it = start; it != end; it++)
cout << *it << " " ;
cout << " }\n" << endl ; //return the last location at which 10 can be inserted
// in Numbers
location = lower_bound(start, end, ) ;
location1 = upper_bound(start, end, ) ; cout << "Element 10 can be inserted at index "
<< location - start<< endl ;
cout << "Element 10 can be inserted at index "
<< location1 - start<< endl ;
}
上一篇:【LINUX命令】之MV


下一篇:iOS开发——高级UI之OC篇&UIdatePicker&UIPickerView简单使用