Index: libs/algorithm/minmax/index.html =================================================================== RCS file: /cvsroot/boost/boost/libs/algorithm/minmax/index.html,v retrieving revision 1.4 diff -u -p -b -B -r1.4 index.html --- libs/algorithm/minmax/index.html 5 Oct 2004 15:45:16 -0000 1.4 +++ libs/algorithm/minmax/index.html 22 Nov 2004 11:30:29 -0000 @@ -1,4 +1,5 @@ - + @@ -10,10 +11,10 @@ -

Header <Header <boost/algorithm/minmax.hpp>

- +
Motivation
Synopsis
@@ -29,11 +30,10 @@ HREF="../../../../boost/minmax.hpp">boos Note about performance
Acknowledgements
- +
- -

+

Motivation

The minmax library is composed of two headers, minmax as straightforward extensions of the C++ standard. As it returns a pair of const&, we must use the Boost.tuple library to construct such -pairs. (Please note: the intent is not to fix the known defaults of +href="../../tuple/index.html">Boost.tuple library to construct such +pairs. (Please note: the intent is not to fix the known faults of std::min -and std::max, but to add one more algorithms that combines both; see the +and std::max, but to add one more algorithm that combines both; see the rationale.)

The second file implements the function templates @@ -81,22 +81,20 @@ all the minmax_element function 3n/2+1 comparisons and exactly n increments of the ForwardIterator.

- - -

+

Synopsis of <boost/algorithm/minmax.hpp>

-
#include <boost/tuple/tuple.hpp>
+
#include <boost/tuple/tuple.hpp>
 
 namespace boost {
 
-  template <class T>
-  tuple<T const&, T const&> >
+  template <class T>
+  tuple<T const&, T const&> >
   minmax(const T& a, const T& b);
 
-  template <class T, class BinaryPredicate>
-  tuple<T const&, T const&> >
+  template <class T, class BinaryPredicate>
+  tuple<T const&, T const&> >
   minmax(const T& a, const T& b, BinaryPredicate comp);
 
 }
@@ -105,16 +103,16 @@ namespace boost {
 

Synopsis of <boost/algorithm/minmax_element.hpp>

-
#include <utility> // for std::pair
+
#include <utility> // for std::pair
 
 namespace boost {
 
-  template <class ForwardIterator>
-  std::pair<ForwardIterator,ForwardIterator>
+  template <class ForwardIterator>
+  std::pair<ForwardIterator,ForwardIterator>
   minmax_element(ForwardIterator first, ForwardIterator last);
 
-  template <class ForwardIterator, class BinaryPredicate>
-  std::pair<ForwardIterator,ForwardIterator>
+  template <class ForwardIterator, class BinaryPredicate>
+  std::pair<ForwardIterator,ForwardIterator>
   minmax_element(ForwardIterator first, ForwardIterator last,
                  BinaryPredicate comp);
 
@@ -134,10 +132,8 @@ which element(s) you want to pick in cas
 I won't bore you with the complete synopsis, they have exactly the same
 declaration as their corresponding _element function. Still,
 you can find the complete synopsis here.
-
 
-
-

+

Function templates description

The minmax algorithm returns a pair p containing either (a,b) @@ -149,7 +145,7 @@ are equivalent, the pair (a,b) is and largest elements in the range [first, last). If there are several instance of these elements, the first one is returned. They are identical to -std::min_element and std::max_elementand +std::min_element and std::max_element and are only included in this library for symmetry.

Last_min_element and last_max_element find the smallest and largest elements in the range [first, last). They are almost @@ -177,18 +173,14 @@ and the second version to:


Note: the first_min_last_max_element can also be described as finding the first and last elements in the range if it were stably sorted. -
- -

+

Definition

Defined in
minmax.hpp and in minmax_element.hpp. - - -

+

Requirements on types

For minmax, T must be a model of
LessThan Comparable. @@ -216,20 +208,16 @@ Predicate. ForwardIterator's value type is convertible to BinaryPredicate's first argument type and second argument type. - - -

+

Preconditions

  • [first, last) is a valid range.
-
- -

+

Postconditions

In addition to the semantic description above. for minmax_element and all the which_min_what_max_element @@ -239,11 +227,9 @@ if and only if [first, last) is return value or both members of the resulting pair are iterators in the range [first, last). -
- -

-Complexity

+

+Complexity

Minmax performs a single comparison and is otherwise of constant complexity. The use of boost::tuple<T const&> prevents copy constructors in case the arguments are passed by reference. @@ -268,10 +254,8 @@ and at most 3(n/2) if n[3] where n is the number of elements in [first,last). - - -

+

Example

This example is included in the distribution in the examples section of the library under @@ -280,26 +264,24 @@ the library under
int main()
 {
   using namespace std;
-  boost::tuple<int const&, int const&> result1 = boost::minmax(1, 0);
+  boost::tuple<int const&, int const&> result1 = boost::minmax(1, 0);
 
   assert( result1.get<0>() == 0 );
   assert( result1.get<1>() == 1 );
 
-  list<int> L;
+  list<int> L;
   generate_n(front_inserter(L), 1000, rand);
 
-  typedef list<int>::const_iterator iterator;
-  pair< iterator, iterator > result2 = boost::minmax_element(L.begin(), L.end());
+  typedef list<int>::const_iterator iterator;
+  pair< iterator, iterator > result2 = boost::minmax_element(L.begin(), L.end());
   cout << "The smallest element is " << *(result2.first) << endl;
   cout << "The largest element is  " << *(result2.second) << endl;
 
   assert( result2.first  == std::min_element(L.begin(), L.end());
   assert( result2.second == std::max_element(L.begin(), L.end());
 }
- - -

+

Notes

[1]We do not support idioms such as tie(a,b)=minmax(a,b) @@ -331,69 +313,68 @@ needs to be compared to the current mini We can avoid the latter comparison if the former is successful, hence the at most instead of exactly in the odd case. - - -

-Rationale:

+

+Rationale

-
-

Why not a single header &boost/algorithm/minmax.hpp>?

+

Why not a single header &boost/algorithm/minmax.hpp>?

This was the design originally proposed and approved in the formal review. As the need for Boost.tuple became clear (due to the limitations of std::pair), it became also annoying to require another library for minmax_element which does not need it. Hence the separation into two header files.

-
-

Your minmax suffers from the same problems as std::min and -std::max.

+ +

Your minmax suffers from the same problems as std::min and +std::max.

I am aware of the problems with std::min and std::max, and all the debate that has been going on (please consult -Alexandrescu's -paper and the links therein). But I don't see the purpose of this +Alexandrescu's paper, + +"Min and Max Redivivus" and the links therein). But I don't see the purpose of this library as fixing something that is part of the C++ standard. I humbly think it's beyond the scope of this library. Rather, I am following the way of the standard in simply providing one more function of the same family. If someone else wants to fix std::min, their fix would probably apply to boost::minmax as well.

- -

Why no min/max_element_if?

+

Why no min/max_element_if?

In a first version of the library, I proposed _if versions of all the algorithms (well, not all, because that would be too much). However, there is simply no reason to do so, and all the versions I had were just as fast implemented using the excellent -<boost/iterator_adaptors.hpp> library. Namely, a call to +<boost/iterator_adaptors.hpp> library. Namely, a call to min_element_if(first, last, pred) would be just as well implemented by: +

      // equivalent to min_element_if(first, last, pred)
      min_element(boost::make_filter_iterator(first, last, pred),
                  boost::make_filter_iterator(last, last, pred));
 
+

Arguably, the min_element_if version is somewhat shorter, but the overhead of iterator adaptors is not large, and they get rid of a lot of code (think of all the combinations between first/last and doubling them with _if variants!).

-

Discussion: about std::max_element

+

Discussion: about std::max_element

This rationale is somewhat historical, but explains why there are all these first/last_min/max_element functions.

The C++ standard mandates that std::min_element and std::max_element return the first instance of the smallest and largest elements (as opposed to, say, the last). This arbitrary choice has some consistency: In the -case of v of type vector<int>, for instance, it is true that std::min_element(v.begin(),v.end(),std::less<int>()) -== std::max_element(v.begin(),v.end(),std::greater<int>()). +case of v of type vector<int>, for instance, it is true that std::min_element(v.begin(),v.end(),std::less<int>()) +== std::max_element(v.begin(),v.end(),std::greater<int>()).

There is of course nothing wrong with this: it's simply a matter of choice. Yet another way to specify min_element and max_element is to define them as the first and the last elements if the range was stably sorted. (The stable sort is necessary to disambiguate between iterators that have the same value.) In that case, min should return the first instance and max should return the last. Then, both functions are related by -reverse_iterator(std::first_min_element(v.begin(),v.end(),std::less<int>())) +reverse_iterator(std::first_min_element(v.begin(),v.end(),std::less<int>())) == -std::last_max_element(v.rbegin(),v.rend(),std::greater<int>()). +std::last_max_element(v.rbegin(),v.rend(),std::greater<int>()). This definition is subtly different from the previous one.

The definition problem surfaces when one tries to design a minmax_element, using the procedure proposed in (Cormen, Leiserson, Rivest: "Introduction @@ -441,14 +422,14 @@ slower than and last_max_element called separately. [2] -

Why algorithms and not accumulators?

+

Why algorithms and not accumulators?

The minmax algorithms are useful in computing the extent of a range. In computer graphics, we need a bounding box of a set of objects. In that case the need for a single pass is even more stringent as all three directions must be done at once. Food for thoughts: there is matter for a nice generic programming library with stackable update_min and update_max function objects which store a reference to the -min_resultand +min_result and max_result variables, in conjunction with the for_each algorithm).

I believe many standard sequential algorithms could be reformulated @@ -458,12 +439,12 @@ do not see it competing with minmax, rat (including minmax) to the accumulator framework. However, I felt it is beyond the scope of this library to provide such accumulators.

- -

This first/last is a perfect application for a policy-based + +

This first/last is a perfect application for a policy-based design.

True, and I could have gone that way, with the default policy for min_element and max_element to pick the first -occurence of the result. This would have thinned the number of +occurrence of the result. This would have thinned the number of combinations of the minmax_element variants. But it would also have meant to change the interface of boost::minmax_element. One of the goals of the minmax_element algorithm is its @@ -476,15 +457,12 @@ adding policies would have meant unfortu standard and created an obstacle towards that goal. Besides, the code remains rather readable and simple without policies. So I am quite happy to keep it like this. -

- +

- -

About performance

- +

About performance

- -

+ +

Acknowledgements

My students in CS903 (Polytechnic Univ.,
http://photon.poly.edu/~hbr/cs903/) who had minmax_element as an assignment helped clarify the issues,