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

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

函数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 = ;
  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[] = ;
  23. Numbers[] = ;
  24. Numbers[] = ;
  25. Numbers[] = ;
  26. Numbers[] = ;
  27. Numbers[] = ;
  28. Numbers[] = ;
  29. Numbers[] = ;
  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, ) ;
  46. location1 = upper_bound(start, end, ) ;
  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. }

STL lower_bound upper_bound binary-search的更多相关文章

  1. [STL]lower_bound&upper_bound

    源码 lower_bound template <class ForwardIterator, class T> ForwardIterator lower_bound (ForwardI ...

  2. C++ STL中的Binary search(二分查找)

    这篇博客转自爱国师哥,这里给出连接https://www.cnblogs.com/aiguona/p/7281856.html 一.解释 以前遇到二分的题目都是手动实现二分,不得不说错误比较多,关于返 ...

  3. STL模板整理 Binary search(二分查找)

    前言: 之前做题二分都是手动二分造轮子,用起来总是差强人意,后来看到STL才发现前辈们早就把轮子造好了,不得不说比自己手动实现好多了. 常用操作 1.头文件 #include <algorith ...

  4. stl lower_bound upper_bound binary_search equal_range

    自己按照stl实现了一个:   http://www.cplusplus.com/reference/algorithm/binary_search/ 这里有个注释,如何判断两个元素相同: Two e ...

  5. 鬼知道是啥系列之——STL(lower_bound(),upper_bound() )

    引子,不明觉厉:   百度,渐入佳境: 头铁,入门到放弃: lower_bound(): 头文件:  #include<algorithm>函数功能:  函数lower_bound()在f ...

  6. STL lower_bound upper_bound 用法

    1.lower_bound(begin,end,x) 返回第一个>=x的位置,找不到return .end() 2.upper_bound (begin,end,x) 返回第一个>x的位置 ...

  7. algorithm@ lower_bound implementation(Binary Search)

    一道来自jhu algorithm的作业题: Given two sorted arrays A, B, give a linear time algorithm that finds two entr ...

  8. [转]C++ STL中的Binary search(二分查找)

    链接地址:https://www.cnblogs.com/wkfvawl/p/9475939.html

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

    Section I正确区分不同的查找算法count,find,binary_search,lower_bound,upper_bound,equal_range 本文是对Effective STL第4 ...

随机推荐

  1. Python For Data Analysis -- Pandas

    首先pandas的作者就是这本书的作者 对于Numpy,我们处理的对象是矩阵 pandas是基于numpy进行封装的,pandas的处理对象是二维表(tabular, spreadsheet-like ...

  2. C#编程总结(四)多线程应用(进度条的编程问题)——转自http://www.cnblogs.com/yank/p/3232955.html

    多线程应用 多线程应用很广泛,简单总结了一下: 1)不阻断主线程,实现即时响应,由后台线程完成特定操作2)多个线程,完成同类任务,提高并发性能3)一个任务有多个独立的步骤,多个线程并发执行各子任务,提 ...

  3. Excel VBA

    =COUNTIF(Y3:Y212,"=11") =SUMIF(Y3:Y212,"=11",AA3:AA212) =SUMPRODUCT((Y3:Y212=&qu ...

  4. Redis学习笔记--五种数据类型的使用场景

    String 1.String 常用命令: 除了get.set.incr.decr mget等操作外,Redis还提供了下面一些操作: 获取字符串长度 往字符串append内容 设置和获取字符串的某一 ...

  5. Qt Model/View(官方翻译,图文并茂)

    http://doc.trolltech.com/main-snapshot/model-view-programming.html 介绍 Qt 4推出了一组新的item view类,它们使用mode ...

  6. mvc EF 数据保存时,报错:”对一个或多个实体的验证失败……“之解决

    在EF5.0添加实体数据到数据库的时候,出现“对一个或多个实体的验证失败.有关详细信息,请参见“EntityValidationErrors”属性这个错误 解决: SaveChanges前先关闭验证实 ...

  7. frameset、frame、noframes和iframe的区别

    原网站地址:http://nmyun.blog.51cto.com/448726/155268 ■ 框架概念 :所谓框架便是网页画面分成几个框窗,同时取得多个 URL.只需要 <frameset ...

  8. SQL PROMPT 取消dbo前缀

    SQL Prompt 无疑大大提高了开发者的效率,高效而简单,特别适合大型的数据库脚本编写,但遗憾得是至今没有可供使用的中文版本.SQL Prompt 默认对象名前面会有 dbo 前缀,在一些场合这样 ...

  9. Linq世界走一走

    什么是Linq?它是用来做什么的?怎么用? Linq的优点是不管数据源是什么,都可以统一查询.换言之,它是一种包含一套标准查询操作符的查询语言,可以对多个数据源进行查询 ⑴Linq俗称语言集成查询(L ...

  10. sql Server 使某一列的值等于行号

    declare @i INT update 表名 SET [列名]=@i,@i=@i+ WHERE 条件