#ifndef __MAX_MIN_H_
#define __MAX_MIN_H_
#include <functional>
#include "max.h"

/* 
 * We refer to A[0], A[1], ..., A[n-1] as the entries of A.  
 * The entries are permuted such that the min is first and the max is last,
 * with the others in unspecified order between.
 *
 * It is assumed that a LessThanFunction defines a strict weak order relation.
 * Min and max in A are determined with respect to this relation, and the 
 * entries of A are permuted such that A[0] is the min and A[n-1] is the max.
 *
 * In other words, max_min permutes elements of A such that for any element x of A, 
 * isLess(x, A[0] is false and isLess(A[n-1], x) is false.
 *
 * The isLess argument is optional.  If it is omitted, operator< is used as isLess.
 * Of course, for this to work, bool operator< (T, T) must be defined.
 */
// Version 1, does 2n-2 comparisons.
template< typename Iterator, typename LessThanFunction >
void max_min_1(Iterator A, size_t n, LessThanFunction& isLess) {
	max(A, n, isLess);
	min(A, n, isLess);
}

// Version 2, may do fewer than 2n-2 comparisons.
template< typename Iterator, typename LessThanFunction >
void max_min_2(Iterator A, size_t n, LessThanFunction& isLess) {
	if (n < 2) return;
	if ( isLess(A[n-1], A[0]) ) 
		std::swap(A[n-1], A[0]);
	for(int i = 1; i < n-1; ++i)
		if ( isLess(A[n-1], A[i]) )
			std::swap(A[n-1], A[i]);
		else if ( isLess(A[i], A[0]) )
			std::swap(A[i], A[0]);
}

// Version 3, fewest comparisons
template< typename Iterator, typename LessThanFunction >
void max_min_3(Iterator A, size_t n, LessThanFunction& isLess)
{
	int f = n/2; // floor
	int c = n - f; // ceiling
	
	for(int i = 1; i < f; ++i)
		if ( isLess(A[c+i], A[i]) )
			std::swap(A[i], A[c+i]);
	// invariant:  none of A[0]..A[f-1] is a max, none of A[c]..A[n-1] is a min.
	max(A + f, c, isLess);
	min(A, c, isLess);
}

#endif // __MAX_MIN_H_
