minmax_element.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. // (C) Copyright Herve Bronnimann 2004.
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. /*
  6. Revision history:
  7. 1 July 2004
  8. Split the code into two headers to lessen dependence on
  9. Boost.tuple. (Herve)
  10. 26 June 2004
  11. Added the code for the boost minmax library. (Herve)
  12. */
  13. #ifndef BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
  14. #define BOOST_ALGORITHM_MINMAX_ELEMENT_HPP
  15. /* PROPOSED STANDARD EXTENSIONS:
  16. *
  17. * minmax_element(first, last)
  18. * Effect: std::make_pair( std::min_element(first, last),
  19. * std::max_element(first, last) );
  20. *
  21. * minmax_element(first, last, comp)
  22. * Effect: std::make_pair( std::min_element(first, last, comp),
  23. * std::max_element(first, last, comp) );
  24. */
  25. #include <utility> // for std::pair and std::make_pair
  26. namespace boost {
  27. namespace detail { // for obtaining a uniform version of minmax_element
  28. // that compiles with VC++ 6.0 -- avoid the iterator_traits by
  29. // having comparison object over iterator, not over dereferenced value
  30. template <typename Iterator>
  31. struct less_over_iter {
  32. bool operator()(Iterator const& it1,
  33. Iterator const& it2) const { return *it1 < *it2; }
  34. };
  35. template <typename Iterator, class BinaryPredicate>
  36. struct binary_pred_over_iter {
  37. explicit binary_pred_over_iter(BinaryPredicate const& p ) : m_p( p ) {}
  38. bool operator()(Iterator const& it1,
  39. Iterator const& it2) const { return m_p(*it1, *it2); }
  40. private:
  41. BinaryPredicate m_p;
  42. };
  43. // common base for the two minmax_element overloads
  44. template <typename ForwardIter, class Compare >
  45. std::pair<ForwardIter,ForwardIter>
  46. basic_minmax_element(ForwardIter first, ForwardIter last, Compare comp)
  47. {
  48. if (first == last)
  49. return std::make_pair(last,last);
  50. ForwardIter min_result = first;
  51. ForwardIter max_result = first;
  52. // if only one element
  53. ForwardIter second = first; ++second;
  54. if (second == last)
  55. return std::make_pair(min_result, max_result);
  56. // treat first pair separately (only one comparison for first two elements)
  57. ForwardIter potential_min_result = last;
  58. if (comp(first, second))
  59. max_result = second;
  60. else {
  61. min_result = second;
  62. potential_min_result = first;
  63. }
  64. // then each element by pairs, with at most 3 comparisons per pair
  65. first = ++second; if (first != last) ++second;
  66. while (second != last) {
  67. if (comp(first, second)) {
  68. if (comp(first, min_result)) {
  69. min_result = first;
  70. potential_min_result = last;
  71. }
  72. if (comp(max_result, second))
  73. max_result = second;
  74. } else {
  75. if (comp(second, min_result)) {
  76. min_result = second;
  77. potential_min_result = first;
  78. }
  79. if (comp(max_result, first))
  80. max_result = first;
  81. }
  82. first = ++second;
  83. if (first != last) ++second;
  84. }
  85. // if odd number of elements, treat last element
  86. if (first != last) { // odd number of elements
  87. if (comp(first, min_result))
  88. min_result = first, potential_min_result = last;
  89. else if (comp(max_result, first))
  90. max_result = first;
  91. }
  92. // resolve min_result being incorrect with one extra comparison
  93. // (in which case potential_min_result is necessarily the correct result)
  94. if (potential_min_result != last
  95. && !comp(min_result, potential_min_result))
  96. min_result = potential_min_result;
  97. return std::make_pair(min_result,max_result);
  98. }
  99. } // namespace detail
  100. template <typename ForwardIter>
  101. std::pair<ForwardIter,ForwardIter>
  102. minmax_element(ForwardIter first, ForwardIter last)
  103. {
  104. return detail::basic_minmax_element(first, last,
  105. detail::less_over_iter<ForwardIter>() );
  106. }
  107. template <typename ForwardIter, class BinaryPredicate>
  108. std::pair<ForwardIter,ForwardIter>
  109. minmax_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  110. {
  111. return detail::basic_minmax_element(first, last,
  112. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  113. }
  114. }
  115. /* PROPOSED BOOST EXTENSIONS
  116. * In the description below, [rfirst,rlast) denotes the reversed range
  117. * of [first,last). Even though the iterator type of first and last may
  118. * be only a Forward Iterator, it is possible to explain the semantics
  119. * by assuming that it is a Bidirectional Iterator. In the sequel,
  120. * reverse(ForwardIterator&) returns the reverse_iterator adaptor.
  121. * This is not how the functions would be implemented!
  122. *
  123. * first_min_element(first, last)
  124. * Effect: std::min_element(first, last);
  125. *
  126. * first_min_element(first, last, comp)
  127. * Effect: std::min_element(first, last, comp);
  128. *
  129. * last_min_element(first, last)
  130. * Effect: reverse( std::min_element(reverse(last), reverse(first)) );
  131. *
  132. * last_min_element(first, last, comp)
  133. * Effect: reverse( std::min_element(reverse(last), reverse(first), comp) );
  134. *
  135. * first_max_element(first, last)
  136. * Effect: std::max_element(first, last);
  137. *
  138. * first_max_element(first, last, comp)
  139. * Effect: max_element(first, last);
  140. *
  141. * last_max_element(first, last)
  142. * Effect: reverse( std::max_element(reverse(last), reverse(first)) );
  143. *
  144. * last_max_element(first, last, comp)
  145. * Effect: reverse( std::max_element(reverse(last), reverse(first), comp) );
  146. *
  147. * first_min_first_max_element(first, last)
  148. * Effect: std::make_pair( first_min_element(first, last),
  149. * first_max_element(first, last) );
  150. *
  151. * first_min_first_max_element(first, last, comp)
  152. * Effect: std::make_pair( first_min_element(first, last, comp),
  153. * first_max_element(first, last, comp) );
  154. *
  155. * first_min_last_max_element(first, last)
  156. * Effect: std::make_pair( first_min_element(first, last),
  157. * last_max_element(first, last) );
  158. *
  159. * first_min_last_max_element(first, last, comp)
  160. * Effect: std::make_pair( first_min_element(first, last, comp),
  161. * last_max_element(first, last, comp) );
  162. *
  163. * last_min_first_max_element(first, last)
  164. * Effect: std::make_pair( last_min_element(first, last),
  165. * first_max_element(first, last) );
  166. *
  167. * last_min_first_max_element(first, last, comp)
  168. * Effect: std::make_pair( last_min_element(first, last, comp),
  169. * first_max_element(first, last, comp) );
  170. *
  171. * last_min_last_max_element(first, last)
  172. * Effect: std::make_pair( last_min_element(first, last),
  173. * last_max_element(first, last) );
  174. *
  175. * last_min_last_max_element(first, last, comp)
  176. * Effect: std::make_pair( last_min_element(first, last, comp),
  177. * last_max_element(first, last, comp) );
  178. */
  179. namespace boost {
  180. // Min_element and max_element variants
  181. namespace detail { // common base for the overloads
  182. template <typename ForwardIter, class BinaryPredicate>
  183. ForwardIter
  184. basic_first_min_element(ForwardIter first, ForwardIter last,
  185. BinaryPredicate comp)
  186. {
  187. if (first == last) return last;
  188. ForwardIter min_result = first;
  189. while (++first != last)
  190. if (comp(first, min_result))
  191. min_result = first;
  192. return min_result;
  193. }
  194. template <typename ForwardIter, class BinaryPredicate>
  195. ForwardIter
  196. basic_last_min_element(ForwardIter first, ForwardIter last,
  197. BinaryPredicate comp)
  198. {
  199. if (first == last) return last;
  200. ForwardIter min_result = first;
  201. while (++first != last)
  202. if (!comp(min_result, first))
  203. min_result = first;
  204. return min_result;
  205. }
  206. template <typename ForwardIter, class BinaryPredicate>
  207. ForwardIter
  208. basic_first_max_element(ForwardIter first, ForwardIter last,
  209. BinaryPredicate comp)
  210. {
  211. if (first == last) return last;
  212. ForwardIter max_result = first;
  213. while (++first != last)
  214. if (comp(max_result, first))
  215. max_result = first;
  216. return max_result;
  217. }
  218. template <typename ForwardIter, class BinaryPredicate>
  219. ForwardIter
  220. basic_last_max_element(ForwardIter first, ForwardIter last,
  221. BinaryPredicate comp)
  222. {
  223. if (first == last) return last;
  224. ForwardIter max_result = first;
  225. while (++first != last)
  226. if (!comp(first, max_result))
  227. max_result = first;
  228. return max_result;
  229. }
  230. } // namespace detail
  231. template <typename ForwardIter>
  232. ForwardIter
  233. first_min_element(ForwardIter first, ForwardIter last)
  234. {
  235. return detail::basic_first_min_element(first, last,
  236. detail::less_over_iter<ForwardIter>() );
  237. }
  238. template <typename ForwardIter, class BinaryPredicate>
  239. ForwardIter
  240. first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  241. {
  242. return detail::basic_first_min_element(first, last,
  243. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  244. }
  245. template <typename ForwardIter>
  246. ForwardIter
  247. last_min_element(ForwardIter first, ForwardIter last)
  248. {
  249. return detail::basic_last_min_element(first, last,
  250. detail::less_over_iter<ForwardIter>() );
  251. }
  252. template <typename ForwardIter, class BinaryPredicate>
  253. ForwardIter
  254. last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  255. {
  256. return detail::basic_last_min_element(first, last,
  257. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  258. }
  259. template <typename ForwardIter>
  260. ForwardIter
  261. first_max_element(ForwardIter first, ForwardIter last)
  262. {
  263. return detail::basic_first_max_element(first, last,
  264. detail::less_over_iter<ForwardIter>() );
  265. }
  266. template <typename ForwardIter, class BinaryPredicate>
  267. ForwardIter
  268. first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  269. {
  270. return detail::basic_first_max_element(first, last,
  271. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  272. }
  273. template <typename ForwardIter>
  274. ForwardIter
  275. last_max_element(ForwardIter first, ForwardIter last)
  276. {
  277. return detail::basic_last_max_element(first, last,
  278. detail::less_over_iter<ForwardIter>() );
  279. }
  280. template <typename ForwardIter, class BinaryPredicate>
  281. ForwardIter
  282. last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp)
  283. {
  284. return detail::basic_last_max_element(first, last,
  285. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  286. }
  287. // Minmax_element variants -- comments removed
  288. namespace detail {
  289. template <typename ForwardIter, class BinaryPredicate>
  290. std::pair<ForwardIter,ForwardIter>
  291. basic_first_min_last_max_element(ForwardIter first, ForwardIter last,
  292. BinaryPredicate comp)
  293. {
  294. if (first == last)
  295. return std::make_pair(last,last);
  296. ForwardIter min_result = first;
  297. ForwardIter max_result = first;
  298. ForwardIter second = ++first;
  299. if (second == last)
  300. return std::make_pair(min_result, max_result);
  301. if (comp(second, min_result))
  302. min_result = second;
  303. else
  304. max_result = second;
  305. first = ++second; if (first != last) ++second;
  306. while (second != last) {
  307. if (!comp(second, first)) {
  308. if (comp(first, min_result))
  309. min_result = first;
  310. if (!comp(second, max_result))
  311. max_result = second;
  312. } else {
  313. if (comp(second, min_result))
  314. min_result = second;
  315. if (!comp(first, max_result))
  316. max_result = first;
  317. }
  318. first = ++second; if (first != last) ++second;
  319. }
  320. if (first != last) {
  321. if (comp(first, min_result))
  322. min_result = first;
  323. else if (!comp(first, max_result))
  324. max_result = first;
  325. }
  326. return std::make_pair(min_result, max_result);
  327. }
  328. template <typename ForwardIter, class BinaryPredicate>
  329. std::pair<ForwardIter,ForwardIter>
  330. basic_last_min_first_max_element(ForwardIter first, ForwardIter last,
  331. BinaryPredicate comp)
  332. {
  333. if (first == last) return std::make_pair(last,last);
  334. ForwardIter min_result = first;
  335. ForwardIter max_result = first;
  336. ForwardIter second = ++first;
  337. if (second == last)
  338. return std::make_pair(min_result, max_result);
  339. if (comp(max_result, second))
  340. max_result = second;
  341. else
  342. min_result = second;
  343. first = ++second; if (first != last) ++second;
  344. while (second != last) {
  345. if (comp(first, second)) {
  346. if (!comp(min_result, first))
  347. min_result = first;
  348. if (comp(max_result, second))
  349. max_result = second;
  350. } else {
  351. if (!comp(min_result, second))
  352. min_result = second;
  353. if (comp(max_result, first))
  354. max_result = first;
  355. }
  356. first = ++second; if (first != last) ++second;
  357. }
  358. if (first != last) {
  359. if (!comp(min_result, first))
  360. min_result = first;
  361. else if (comp(max_result, first))
  362. max_result = first;
  363. }
  364. return std::make_pair(min_result, max_result);
  365. }
  366. template <typename ForwardIter, class BinaryPredicate>
  367. std::pair<ForwardIter,ForwardIter>
  368. basic_last_min_last_max_element(ForwardIter first, ForwardIter last,
  369. BinaryPredicate comp)
  370. {
  371. if (first == last) return std::make_pair(last,last);
  372. ForwardIter min_result = first;
  373. ForwardIter max_result = first;
  374. ForwardIter second = first; ++second;
  375. if (second == last)
  376. return std::make_pair(min_result,max_result);
  377. ForwardIter potential_max_result = last;
  378. if (comp(first, second))
  379. max_result = second;
  380. else {
  381. min_result = second;
  382. potential_max_result = second;
  383. }
  384. first = ++second; if (first != last) ++second;
  385. while (second != last) {
  386. if (comp(first, second)) {
  387. if (!comp(min_result, first))
  388. min_result = first;
  389. if (!comp(second, max_result)) {
  390. max_result = second;
  391. potential_max_result = last;
  392. }
  393. } else {
  394. if (!comp(min_result, second))
  395. min_result = second;
  396. if (!comp(first, max_result)) {
  397. max_result = first;
  398. potential_max_result = second;
  399. }
  400. }
  401. first = ++second;
  402. if (first != last) ++second;
  403. }
  404. if (first != last) {
  405. if (!comp(min_result, first))
  406. min_result = first;
  407. if (!comp(first, max_result)) {
  408. max_result = first;
  409. potential_max_result = last;
  410. }
  411. }
  412. if (potential_max_result != last
  413. && !comp(potential_max_result, max_result))
  414. max_result = potential_max_result;
  415. return std::make_pair(min_result,max_result);
  416. }
  417. } // namespace detail
  418. template <typename ForwardIter>
  419. inline std::pair<ForwardIter,ForwardIter>
  420. first_min_first_max_element(ForwardIter first, ForwardIter last)
  421. {
  422. return minmax_element(first, last);
  423. }
  424. template <typename ForwardIter, class BinaryPredicate>
  425. inline std::pair<ForwardIter,ForwardIter>
  426. first_min_first_max_element(ForwardIter first, ForwardIter last,
  427. BinaryPredicate comp)
  428. {
  429. return minmax_element(first, last, comp);
  430. }
  431. template <typename ForwardIter>
  432. std::pair<ForwardIter,ForwardIter>
  433. first_min_last_max_element(ForwardIter first, ForwardIter last)
  434. {
  435. return detail::basic_first_min_last_max_element(first, last,
  436. detail::less_over_iter<ForwardIter>() );
  437. }
  438. template <typename ForwardIter, class BinaryPredicate>
  439. inline std::pair<ForwardIter,ForwardIter>
  440. first_min_last_max_element(ForwardIter first, ForwardIter last,
  441. BinaryPredicate comp)
  442. {
  443. return detail::basic_first_min_last_max_element(first, last,
  444. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  445. }
  446. template <typename ForwardIter>
  447. std::pair<ForwardIter,ForwardIter>
  448. last_min_first_max_element(ForwardIter first, ForwardIter last)
  449. {
  450. return detail::basic_last_min_first_max_element(first, last,
  451. detail::less_over_iter<ForwardIter>() );
  452. }
  453. template <typename ForwardIter, class BinaryPredicate>
  454. inline std::pair<ForwardIter,ForwardIter>
  455. last_min_first_max_element(ForwardIter first, ForwardIter last,
  456. BinaryPredicate comp)
  457. {
  458. return detail::basic_last_min_first_max_element(first, last,
  459. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  460. }
  461. template <typename ForwardIter>
  462. std::pair<ForwardIter,ForwardIter>
  463. last_min_last_max_element(ForwardIter first, ForwardIter last)
  464. {
  465. return detail::basic_last_min_last_max_element(first, last,
  466. detail::less_over_iter<ForwardIter>() );
  467. }
  468. template <typename ForwardIter, class BinaryPredicate>
  469. inline std::pair<ForwardIter,ForwardIter>
  470. last_min_last_max_element(ForwardIter first, ForwardIter last,
  471. BinaryPredicate comp)
  472. {
  473. return detail::basic_last_min_last_max_element(first, last,
  474. detail::binary_pred_over_iter<ForwardIter,BinaryPredicate>(comp) );
  475. }
  476. } // namespace boost
  477. #endif // BOOST_ALGORITHM_MINMAX_ELEMENT_HPP