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进行比较。

具体分析见源码:

  1 //这是forward版本
  2 template <class ForwardIterator, class T>
  3 inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
  4                                    const T& value) {
  5   return __lower_bound(first, last, value, distance_type(first),
  6                        iterator_category(first));
  7 }
  8
  9 // 这是版本一的 forward_iterator 版本
 10 template <class ForwardIterator, class T, class Distance>
 11 ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
 12                               const T& value, Distance*,
 13                               forward_iterator_tag) {
 14   Distance len = 0;
 15   distance(first, last, len);    // 求取整个范围的长度,ForwardIterator没有-n操作
 16   Distance half;
 17   ForwardIterator middle;
 18
 19   while (len > 0) {                        //为了跳出循环,而定义了len,如果用while(true) 然后每次判定长度在break,也行,不过没这个好
 20     half = len >> 1;            // 除以2,注意这种移位写法,不需编译器进行优化
 21     middle = first;                 // 这两行令middle 指向中间位置
 22     advance(middle, half);       //ForwardIterator没有+n的操作
 23     if (*middle < value) {        // 如果中间位置的元素值 < 标的值,value在后半区间
 24       first = middle;            // 这两行令 first 指向 middle 的下一位置
 25       ++first;
 26       len = len - half - 1;        // 修正 len,回头测试循环条件
 27     }
 28 else                        // 注意如果是相等的话,那么执行的是else语句,在前半部分找
 29                             // 与opper_bound进行比较
 30       len = half;                // 修正 len,回头测试循环条件
 31   }
 32   return first;
 33 }
 34 // 这是带comp反函数的 forward_iterator 版本
 35 template <class ForwardIterator, class T, class Compare, class Distance>
 36 ForwardIterator __lower_bound(ForwardIterator first, ForwardIterator last,
 37                               const T& value, Compare comp, Distance*,
 38                               forward_iterator_tag) {
 39   Distance len = 0;
 40   distance(first, last, len);
 41   Distance half;
 42   ForwardIterator middle;
 43
 44   while (len > 0) {
 45     half = len >> 1;
 46     middle = first;
 47     advance(middle, half);
 48     if (comp(*middle, value)) {
 49       first = middle;
 50       ++first;
 51       len = len - half - 1;
 52     }
 53     else
 54       len = half;
 55   }
 56   return first;
 57 }
 58
 59 // 这是random_access_iterator版本
 60 template <class ForwardIterator, class T, class Compare>
 61 inline ForwardIterator lower_bound(ForwardIterator first, ForwardIterator last,
 62                                    const T& value, Compare comp) {
 63   return __lower_bound(first, last, value, comp, distance_type(first),
 64                        iterator_category(first));
 65 }
 66
 67 // 这是版本一的 random_access_iterator 版本
 68 template <class RandomAccessIterator, class T, class Distance>
 69 RandomAccessIterator __lower_bound(RandomAccessIterator first,
 70                                    RandomAccessIterator last, const T& value,
 71                                    Distance*, random_access_iterator_tag) {
 72   Distance len = last - first;    //求取整个范围的长度,与ForwarIterator版本进行比较
 73   Distance half;
 74   RandomAccessIterator middle;
 75
 76   while (len > 0) {
 77 half = len >> 1;
 78 middle = first + half;
 79     if (*middle < value) {
 80       first = middle + 1;
 81       len = len - half - 1;        //修正 len,回头测试循环条件,RamdonAccessIterator版本
 82     }
 83     else
 84       len = half;
 85   }
 86   return first;
 87 }
 88
 89
 90
 91 //这是带comp仿函数 random_access_iterator 版本
 92 template <class RandomAccessIterator, class T, class Compare, class Distance>
 93 RandomAccessIterator __lower_bound(RandomAccessIterator first,
 94                                    RandomAccessIterator last,
 95                                    const T& value, Compare comp, Distance*,
 96                                    random_access_iterator_tag) {
 97   Distance len = last - first;
 98   Distance half;
 99   RandomAccessIterator middle;
100
101   while (len > 0) {
102     half = len >> 1;
103     middle = first + half;
104     if (comp(*middle, value)) {
105       first = middle + 1;
106       len = len - half - 1;
107     }
108     else
109       len = half;
110   }
111   return first;
112 }
113
114 // 这是forward_iterator版本
115 template <class ForwardIterator, class T>
116 inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
117                                    const T& value) {
118   return __upper_bound(first, last, value, distance_type(first),
119                        iterator_category(first));
120 }
121
122 // 这是版本一的 forward_iterator 版本
123 template <class ForwardIterator, class T, class Distance>
124 ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
125                               const T& value, Distance*,
126                               forward_iterator_tag) {
127   Distance len = 0;
128   distance(first, last, len);
129   Distance half;
130   ForwardIterator middle;
131
132   while (len > 0) {
133     half = len >> 1;
134     middle = first;
135     advance(middle, half);
136     if (value < *middle)        // 如果中间位置的元素值大于标的值,证明在前半部分
137       len = half;                // 修正len
138 else {                        // 注意如果元素值相等的话,那么是在后半部分找
139                             // 与lower_bound进行比较
140       first = middle;            // 在下半部分,令first指向middle的下一个位置
141       ++first;
142       len = len - half - 1;        // 修正 len
143     }
144   }
145   return first;
146 }
147
148 // 这是版本一的 random_access_iterator 版本
149 template <class RandomAccessIterator, class T, class Distance>
150 RandomAccessIterator __upper_bound(RandomAccessIterator first,
151                                    RandomAccessIterator last, const T& value,
152                                    Distance*, random_access_iterator_tag) {
153   Distance len = last - first;
154   Distance half;
155   RandomAccessIterator middle;
156
157   while (len > 0) {
158     half = len >> 1;
159     middle = first + half;
160     if (value < *middle)
161       len = half;
162      else {
163       first = middle + 1;
164       len = len - half - 1;
165     }
166   }
167   return first;
168 }
169
170 // 这是带comp的版本
171 template <class ForwardIterator, class T, class Compare>
172 inline ForwardIterator upper_bound(ForwardIterator first, ForwardIterator last,
173                                    const T& value, Compare comp) {
174   return __upper_bound(first, last, value, comp, distance_type(first),
175                        iterator_category(first));
176 }
177
178 // 这是带comp的 forward_iterator 版本
179 template <class ForwardIterator, class T, class Compare, class Distance>
180 ForwardIterator __upper_bound(ForwardIterator first, ForwardIterator last,
181                               const T& value, Compare comp, Distance*,
182                               forward_iterator_tag) {
183   Distance len = 0;
184   distance(first, last, len);
185   Distance half;
186   ForwardIterator middle;
187
188   while (len > 0) {
189     half = len >> 1;
190     middle = first;
191     advance(middle, half);
192     if (comp(value, *middle))
193       len = half;
194     else {
195       first = middle;
196       ++first;
197       len = len - half - 1;
198     }
199   }
200   return first;
201 }
202
203 // 这是带comp的 random_access_iterator 版本
204 template <class RandomAccessIterator, class T, class Compare, class Distance>
205 RandomAccessIterator __upper_bound(RandomAccessIterator first,
206                                    RandomAccessIterator last,
207                                    const T& value, Compare comp, Distance*,
208                                    random_access_iterator_tag) {
209   Distance len = last - first;
210   Distance half;
211   RandomAccessIterator middle;
212
213   while (len > 0) {
214     half = len >> 1;
215     middle = first + half;
216     if (comp(value, *middle))
217       len = half;
218     else {
219       first = middle + 1;
220       len = len - half - 1;
221     }
222   }
223   return first;
224 }
225
226 // 版本一
227 template <class ForwardIterator, class T>
228 bool binary_search(ForwardIterator first, ForwardIterator last,
229                    const T& value) {
230   ForwardIterator i = lower_bound(first, last, value);
231 //这里的实现就是调用的lower_bound ,并且如果元素不存在那么lower_bound指向的元素一定是
232 //operator < 为ture的地方。
233   return i != last && !(value < *i);
234 }
235
236 // 版本二
237 template <class ForwardIterator, class T, class Compare>
238 bool binary_search(ForwardIterator first, ForwardIterator last, const T& value,
239                    Compare comp) {
240   ForwardIterator i = lower_bound(first, last, value, comp);
241   return i != last && !comp(value, *i);
242 }

函数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的位置是越界的!!~

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

测试代码如下:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <functional>
 4 #include <vector>
 5
 6 using namespace std;
 7
 8
 9 int main()
10 {
11     const int VECTOR_SIZE = 8 ;
12
13     // Define a template class vector of int
14     typedef vector<int > IntVector ;
15
16     //Define an iterator for template class vector of strings
17     typedef IntVector::iterator IntVectorIt ;
18
19     IntVector Numbers(VECTOR_SIZE) ;
20
21     IntVectorIt start, end, it, location ;
22
23     // Initialize vector Numbers
24     Numbers[0] = 4 ;
25     Numbers[1] = 10;
26     Numbers[2] = 11 ;
27     Numbers[3] = 30 ;
28     Numbers[4] = 69 ;
29     Numbers[5] = 70 ;
30     Numbers[6] = 96 ;
31     Numbers[7] = 100;
32
33     start = Numbers.begin() ;   // location of first
34                                 // element of Numbers
35
36     end = Numbers.end() ;       // one past the location
37                                 // last element of Numbers
38
39     // print content of Numbers
40     cout << "Numbers { " ;
41     for(it = start; it != end; it++)
42         cout << *it << " " ;
43     cout << " }\n" << endl ;
44
45     // return the first location at which 10 can be inserted
46     // in Numbers
47     location = lower_bound(start, end, 1) ;
48
49     cout << "First location element 10 can be inserted in Numbers is: "
50         << location - start<< endl ;
51 }

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

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

测试代码如下:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <functional>
 4 #include <vector>
 5 using namespace std;
 6
 7 void main()
 8 {
 9     const int VECTOR_SIZE = 8 ;
10
11     // Define a template class vector of int
12     typedef vector<int, allocator<int> > IntVector ;
13
14     //Define an iterator for template class vector of strings
15     typedef IntVector::iterator IntVectorIt ;
16
17     IntVector Numbers(VECTOR_SIZE) ;
18
19     IntVectorIt start, end, it, location, location1;
20
21     // Initialize vector Numbers
22     Numbers[0] = 4 ;
23     Numbers[1] = 10;
24     Numbers[2] = 10 ;
25     Numbers[3] = 30 ;
26     Numbers[4] = 69 ;
27     Numbers[5] = 70 ;
28     Numbers[6] = 96 ;
29     Numbers[7] = 100;
30
31     start = Numbers.begin() ;   // location of first
32                                 // element of Numbers
33
34     end = Numbers.end() ;       // one past the location
35                                 // last element of Numbers
36
37     // print content of Numbers
38     cout << "Numbers { " ;
39     for(it = start; it != end; it++)
40         cout << *it << " " ;
41     cout << " }\n" << endl ;
42
43     //return the last location at which 10 can be inserted
44     // in Numbers
45     location = lower_bound(start, end, 9) ;
46     location1 = upper_bound(start, end, 10) ;
47
48     cout << "Element 10 can be inserted at index "
49         << location - start<< endl ;
50      cout << "Element 10 can be inserted at index "
51         << location1 - start<< endl ;
52 }

时间: 2024-11-07 16:39:38

STL lower_bound upper_bound binary-search的相关文章

Binary Search 的递归与迭代实现及STL中的搜索相关内容

与排序算法不同,搜索算法是比较统一的,常用的搜索除hash外仅有两种,包括不需要排序的线性搜索和需要排序的binary search. 首先介绍一下binary search,其原理很直接,不断地选取有序数组的组中值,比较组中值与目标的大小,继续搜索目标所在的一半,直到找到目标,递归算法可以很直观的表现这个描述: int binarySearchRecursive(int A[], int low, int high, int key) { if (low > high) return -1;

STL之二分查找 (Binary search in STL)

STL之二分查找 (Binary search in STL) Section I正确区分不同的查找算法count,find,binary_search,lower_bound,upper_bound,equal_range 本文是对Effective STL第45条的一个总结,阐述了各种查找算法的异同以及使用他们的时机. 首先可供查找的算法大致有count,find,binary_search,lower_bound,upper_bound,equal_range.带有判别式的如count_i

【转】STL之二分查找 (Binary search in STL)

Section I正确区分不同的查找算法count,find,binary_search,lower_bound,upper_bound,equal_range 本文是对Effective STL第45条的一个总结,阐述了各种查找算法的异同以及使用他们的时机. 首先可供查找的算法大致有count,find,binary_search,lower_bound,upper_bound,equal_range.带有判别式的如count_if,find_if或者binary_search的派别式版本,其

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

关于STL中的排序和检索,排序一般用sort函数即可,今天来整理一下检索中常用的函数——lower_bound , upper_bound 和 binary_search . STL中关于二分查找的函数有三个lower_bound .upper_bound .binary_search .这三个函数都运用于有序区间(当然这也是运用二分查找的前提). Tips:1.在检索前,应该用sort函数对数组进行从小到大排序.     2.使用以上函数时必须包含头文件:#include < algorith

泛型Binary Search Tree实现,And和STL map比较的经营业绩

问题叙述性说明: 1.binary search tree它是一种二进制树的.对于key值.比当前节点左孩子少大于右子. 2.binary search tree不是自平衡树.所以,当插入数据不是非常随机时候,性能会接近O(N).N是树中节点数目; 3.理想状态下.时间复杂度是O(lgN), N是树中节点的数目: 4.以下给出一个简单的实现,并比較其和STL map的性能.一样的操作,大约耗时为STL map 的2/3. 代码例如以下: #ifndef _BINARY_SEARCH_TREE_H

[STL] lower_bound和upper_bound

STL中的每个算法都非常精妙, ForwardIter lower_bound(ForwardIter first, ForwardIter last,const _Tp& val)算法返回一个非递减序列[first, last)中的第一个大于等于值val的位置. ForwardIter upper_bound(ForwardIter first, ForwardIter last, const _Tp& val)算法返回一个非递减序列[first, last)中第一个大于val的位置.

stl(GCC4.9.3 in MinGW)中rbtree lower_bound/upper_bound 的实现

STL内部实现的rbtree,实现 lower_bound/upper_bound 过程,是从 begin() 开始向 end() 进行遍历,将元素的 key 与目标 key 进行比较,直至找到的第一个符合要求的 iterator 为止!具体看代码,如下 位于bits/stl_tree.h 1 template<typename _Key, typename _Val, typename _KeyOfValue, 2 typename _Compare, typename _Alloc> 3

泛型的Binary Search Tree的实现,并与STL map进行操作性能上的比较

问题描述: 1.binary search tree是一种排序二叉树.对于key值,当前节点的小于左孩子的大于右孩子的: 2.binary search tree不是自平衡树.所以,当插入数据不是很随机时候,性能会接近O(N),N是树中节点数目; 3.理想状态下,时间复杂度是O(lgN), N是树中节点的数目: 4.下面给出一个简单的实现,并比较其和STL map的性能,一样的操作,大约耗时为STL map 的2/3: 代码如下: #ifndef _BINARY_SEARCH_TREE_H_ #

my understanding of (lower bound,upper bound) binary search, in C++, thanks to two post

thanks to A simple CPP solution with lower_bound and C++ O(logn) Binary Search that handles duplicate, thanks to phu1ku 's answer on the second post. http://en.cppreference.com/w/cpp/algorithm/upper_bound Returns an iterator pointing to the first ele