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

 

你可能感兴趣的:(search)