/* Karol Kurcz J1TIZ

Minimax oblicza równocześnie wartości minimalne i maksymalne, eliminując potrzebę
stosowania dwóch porównań z użyciem szablonów std::max i std::min. Bibliotek składa
się z dwóch nagłówków <boost/algorithm/minimax.hpp> oraz <boost/algorithm/minimax_element.hpp>
Dla obliczenia wartości minimalnej i maksymalnej w parze liczb wystarcza jedno porównanie.
Dla przedziału n-elementowego wykonywanych jest tylko 3n/2+1 porównań, w porównaniu do 2n porównań
wymaganych przy użyciu std:min_element i std::max_element.

Autorem Minimax jest Hervé Brönnimann.

*/

#include <vector>
#include <algorithm>		// zawiera min_element, max_element
#include <cassert>
#include <iostream>
#include <utility>			// zawiera pair

#include <boost/algorithm/minmax.hpp>
#include <boost/algorithm/minmax_element.hpp>
#include <boost/tuple/tuple.hpp>

int main()
{
	using namespace std;

	/*
	Metoda minmax(const T& a, const T& b) zawarta w nagłówku <boost/algorithm/minmax.hpp> porównuje
	dwa elementy wybierając mniejszy i większy spośród nich. Para jest zwracana w postaci krotki
	wykorzystującej bibliotekę Tuple.
	(więcej o niej http://staff.elka.pw.edu.pl/~rnowak2/zprwiki/doku.php?id=tuple)
	*/

	boost::tuple<int const&, int const&> wynik1 = boost::minmax(10, 1);
	assert( wynik1.get<0>() == 1 );			// element mniejszy z pary (10, 1)
	assert( wynik1.get<1>() == 10 );		// element wiekszy z pary (10, 1)

	cout << "Wykorzystanie metody minimax na parze (10, 1)" << endl;
	cout << "\tmniejszy element to:\t" << wynik1.get<0>() << endl;
	cout << "\twiekszy element to:\t" << wynik1.get<1>() << endl << endl;

	/*
	Istnieje również metoda minmax z dodatkowym (trzecim argumentem) będącym funkcją zwracającą
	wartość logiczną porównania dwóch elementów - minmax(const T& a, const T& b, BinaryPredicate comp)
	więcej o porównaniu http://www.sgi.com/tech/stl/BinaryPredicate.html
	*/


	/*
	Metoda minmax_element(ForwardIterator first, ForwardIterator last) zawarta w nagłówku
	<boost/algorithm/minmax_element.hpp> wyszukuje wartość największą i najmniejszą z obiektu danego kontenera.
	Para jest zwracana jako obiekt pair z biblioteki standardowej.
	*/

	vector<int> vv;
	for(int i = 0; i < 10; ++i){
		vv.push_back(rand() % 10);
		}

	typedef vector<int>::const_iterator iterator;
	pair<iterator, iterator> wynik2 = boost::minmax_element(vv.begin(), vv.end());

	assert( wynik2.first  == std::min_element(vv.begin(), vv.end()) );
	assert( wynik2.second == std::max_element(vv.begin(), vv.end()) );

	cout << "Wykorzystanie metody minimax_element na wektorze:" << endl;
	cout << "\t( ";
	iterator it = vv.begin();
	while(it != vv.end()){
		cout << *it << " ";
		it++;
		}
	cout << ")" << endl;
	cout << "\tnajmniejszy element to:\t" << *(wynik2.first) << endl;
	cout << "\tnajwiekszy element to:\t" << *(wynik2.second) << endl;

	/*
	Tak jak w przypadku metody minimax, dla minimax_elements również jest metoda zawierająca trzeci
	argument - minmax_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp),
	której wykorzystanie jest analogiczne jak w przypadku minimax.
	*/

	/*
	Istnieje również szereg odmian metody minimax_element:
	ForwardIterator first_min_element(ForwardIterator first, ForwardIterator last);
	ForwardIterator first_min_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	ForwardIterator last_min_element(ForwardIterator first, ForwardIterator last);
	ForwardIterator last_min_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	ForwardIterator first_max_element(ForwardIterator first, ForwardIterator last);
	ForwardIterator first_max_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	ForwardIterator last_max_element(ForwardIterator first, ForwardIterator last);
	ForwardIterator last_max_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	first_min_first_max_element(ForwardIterator first, ForwardIterator last);
	first_min_first_max_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	first_min_last_max_element(ForwardIterator first, ForwardIterator last);
	first_min_last_max_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	last_min_first_max_element(ForwardIterator first, ForwardIterator last);
	last_min_first_max_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	last_min_last_max_element(ForwardIterator first, ForwardIterator last);
	last_min_last_max_element(ForwardIterator first, ForwardIterator last, BinaryPredicate comp);
	
	Są one użyteczne w sytuacji, gdy w przeszukiwanym zbiorze znajduje się parę największych lub najmniejszych
	elementów. Metody te ozsztrzygają, który element mamy brać pod uwagę i np. first_min_last_max oznacza, że
	iteratory określające wynik działania metody będą wskazywać na pierwszy minimalny element w kontenerze oraz
	ostatni maksymalny element.
	Standardowa funkcja minmax_element działa jak first_min_first_max_element.
	*/

}
