zoukankan      html  css  js  c++  java
  • 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 }
    View Code

    函数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 << " }
    " << 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 }
    View Code

    函数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 << " }
    " << 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 }
    View Code
  • 相关阅读:
    【漏洞分析】5次shift漏洞破解win7密码
    skyler实战渗透笔记(五)—Tr0ll
    skyler实战渗透笔记(四)—Raven2
    skyler实战渗透笔记(三)—Raven
    python读写excel文件
    python_列表
    mysql安装教程
    centos7安装RabbitMQ教程
    centos7安装mongodb4.2.15教程
    tomcat9安装教程
  • 原文地址:https://www.cnblogs.com/jeff-wgc/p/4462819.html
Copyright © 2011-2022 走看看