#include <iostream>  // `cin', `cout' et `cerr'.
#include <fstream>   // ifstream.
#include <iterator>  // istream_iterator
#include <algorithm> // sort(...) de la STL.
#include <vector>    // Vecteurs de la STL.
#include <cmath>     // _isnan(...)

using namespace std ;

double
mediane_1(const string & nom)
{
	const size_t MAX = 10000 ; // Nombre maximum de nombres.
	double tableau[MAX] ;      // Tableau pour stocker les nombres.
	size_t nombre = 0 ;        // Indice dans tableau[] ; puis nombre de nombres.
	ifstream fichier(nom.c_str()) ;
	if ( ! fichier ) {
		cerr << "Impossible d'ouvrir en lecture `" << nom << "'." << endl ;
		return 0./0. ; }
	double tmp ;
	while ( fichier >> tmp ) {
		if ( nombre == MAX ) {
			cerr << "Désolé, il y a trop de nombres ; le maximum est " << MAX << '.' << endl ;
			return 0./0. ; }
		tableau[nombre] = tmp ;
		++ nombre ; }
	if ( nombre == 0 ) {
		cerr << "Aucun nombre lu dans le fichier." << endl ;
		return 0./0. ; }
	sort(tableau, tableau+nombre) ;
	if ( nombre % 2 == 0 ) {
		// Interpolation linéaire si l'effectif est pair.
		return .5*tableau[nombre/2-1] + .5*tableau[nombre/2] ; }
	else {
		return  tableau[nombre/2] ; }
}
double
mediane_2(const string & nom)
{
	const size_t QUANTUM = 5 ; // Incrément pour la réallocation.
	double * tableau ;           // Pointeur sur l'emplacement obtenu par `new'.
	size_t max = 0 ;             // Nombre courant maximum de nombres.
	size_t nombre = 0 ;          // Indice puis nombre de nombres.
	
	ifstream fichier(nom.c_str()) ;
	if ( ! fichier ) {
		cerr << "Impossible d'ouvrir en lecture `" << nom << "'." << endl ;
		return 0./0. ; }
	double tmp ;
	while ( fichier >> tmp ) {
		if ( nombre == max ) // Oups, il faut réallouer.
		{
			cout << "Oups, réallocation " << nombre << ' ' << max << endl ;
			// L'opérateur `new' permet d'obtenir une région de mémoire, allouée sur le tas.
			double * nouveau = new double[max+QUANTUM] ;
			// L'opérateur `new' retourne un pointeur nul en cas d'échec.
			if ( nouveau == 0 ) {
				// Ne pas oublier de rendre l'ancienne région, sinon "fuite de mémoire".
				if ( nombre > 0 ) {
					delete tableau ; }
				cerr << "Impossible d'allouer de la mémoire sur le tas." << endl ;
				return 0./0. ; }
			// Recopie de l'ancienne région.
			if ( nombre > 0 ) {
				for ( size_t i = 0 ; i < nombre ; ++ i ) {
					nouveau[i] = tableau[i] ; }
				delete tableau ; } // On rend au système d'exploitation l'ancienne région.
			tableau = nouveau ;  // Le pointeur désigne maintenant la nouvelle région.
			max += QUANTUM ;
		}
		tableau[nombre] = tmp ;
		++ nombre ;
	}
	if ( nombre == 0 ) {
		cerr << "Aucun nombre lu dans le fichier." << endl ;
		return 0./0. ; }
	sort(tableau, tableau+nombre) ;
	double valeur ;
	if ( nombre % 2 == 0 ) {
		// Interpolation linéaire si l'effectif est pair.
		valeur = .5*tableau[nombre/2-1] + .5*tableau[nombre/2] ; }
	else {
		valeur = tableau[nombre/2] ; }
	delete tableau ; // Ne pas oublier de rendre la région utilisée.
	return valeur ;
}
double
mediane_3(const string & nom)
{
	ifstream fichier(nom.c_str()) ;
	if ( ! fichier ) {
		cerr << "Impossible d'ouvrir en lecture `" << nom << "'." << endl ;
		return 0./0. ; }
	typedef vector<double> Vecteur ;
	// `vecteur' est construit en appelant l'itérateur d'entrée de `double' du fichier
	// en lecture `fichier'. La syntaxe `Vecteur vecteur(..., ...) ;' ne convient pas ;
	// il s'agit de la  déclaration de la fonction `vecteur' qui retourne un `Vecteur'.
	// Pour faire plus simple mais moins concis, on aurait pu coder :
	//          Vecteur vecteur ;
	//          double tmp ;
	//          while ( fichier >> tmp ) {
	//               vecteur.push_back(tmp) ; }
	Vecteur vecteur((istream_iterator<double>(fichier)), istream_iterator<double>()) ;
	if ( vecteur.empty() ) {
		cerr << "Aucun nombre lu dans le fichier." << endl ;
		return 0./0. ; }
	sort(vecteur.begin(), vecteur.end()) ;
	if ( vecteur.size() % 2 == 0 ) {
		// Interpolation linéaire si l'effectif est pair.
		return .5*vecteur[vecteur.size()/2-1] + .5*vecteur[vecteur.size()/2] ; }
	else {
		return  vecteur[vecteur.size()/2] ; }
}
int
main()
{
	// Test de l'appel de la fonction sur un fichier inexistant.
	double mediane = mediane_1("fichier inexistant") ;
	// La fonction `_isnan(...)' est une extension ; ce n'est donc pas portable.
	if ( _isnan(mediane) ) {
		cout << "La médiane n'a pas pu être calculée." << endl ; }
	else {
		cout << "La médiane est " << mediane << '.' << endl ; }
	// Illustration ; le fichier est constitué de la séquence 0, 1, ..., 10.
	cout << "La médiane est " << mediane_1("médiane.txt") << '.' << endl ;
	cout << "La médiane est " << mediane_2("médiane.txt") << '.' << endl ;
	cout << "La médiane est " << mediane_3("médiane.txt") << '.' << endl ;
	return 0 ; // Retour au système d'exploitation avec le code `0'.
}
