You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
619 lines
14 KiB
619 lines
14 KiB
/**
|
|
* @file Ensemble.hh
|
|
* @author Nicolas MASSE & Thomas LIMIN
|
|
* @date Thu Nov 18
|
|
*
|
|
* @brief Declaration de la classe parametree Ensemble.
|
|
*
|
|
*/
|
|
#ifndef ENSEMBLE_H
|
|
#define ENSEMBLE_H
|
|
|
|
#include <iostream>
|
|
#include <ostream>
|
|
|
|
/* using namespace std;
|
|
*
|
|
* NOTE :
|
|
* Ce fichier d'en-tete ne comporte pas de directive using, bien que la version
|
|
* fournie en comporte. En effet, l'usage de cette directive dans un fichier
|
|
* d'en-tete (dont la finalite est d'etre inclus dans un fichier source) peut creer
|
|
* des conflits d'espace de noms dans les fichiers l'incluant. On preferera
|
|
* l'utilisation des prefixe d'espace de noms
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Extension (iterateur, foncteur)
|
|
* Classe foncteur. Ses instances peuvent etre appelees
|
|
* comme des fonctions race à la surcharge de l'opérateur ()
|
|
* l'implémentation courante retourne le double de l'element
|
|
* passé a cette fonction
|
|
*/
|
|
|
|
template <typename T>
|
|
|
|
class Foncteur {
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructeur. Permet de definir le coefficient de multiplication
|
|
* propre au foncteur
|
|
*
|
|
* @param coef le coefficient
|
|
*/
|
|
Foncteur(double coef) : _coef(coef) {}
|
|
|
|
/**
|
|
* Une methode foncteur, retourne le double de l'elemet
|
|
* passe en parametre. Ceci ne fonctionne que pour les
|
|
* types de données qpossédant un opérateur *
|
|
*
|
|
* @param e l'element a traiter
|
|
* @return l'element retourne
|
|
*/
|
|
T operator() (const T & e) {
|
|
return e * _coef;
|
|
}
|
|
|
|
private:
|
|
|
|
double _coef;
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Classe permettant de representer un ensemble d'elements
|
|
* en utilisant uniquement la notion d'egalite entre elements
|
|
* Aucune relation d'ordre n'est utilisee (par exemple
|
|
* pour avoir un representation ordonnee en memoire qui accelererait
|
|
* les recherches).<br>
|
|
* Seul l'operateur == est utilise pour tester l'egalite de deux
|
|
* elements.
|
|
*/
|
|
|
|
template <typename T>
|
|
|
|
class Ensemble {
|
|
|
|
private:
|
|
|
|
/**
|
|
* Concept de noeud d'une liste chainée. Cette clase est définnie a l'interieur
|
|
* de la classe ensemble, ce qui permet d'en limiter la portée a la classe
|
|
* Ensemble
|
|
*/
|
|
|
|
class Noeud {
|
|
|
|
private:
|
|
T _valeur;
|
|
Noeud * _suivant;
|
|
|
|
public:
|
|
Noeud(const T & valeur, Noeud * suivant = 0) : _valeur(valeur), _suivant(suivant) { }
|
|
|
|
Noeud(const Noeud & n) {
|
|
_valeur = n.getValeur();
|
|
|
|
if (n.aUnSuivant()) {
|
|
_suivant = new Noeud(*n.getSuivant());
|
|
} else {
|
|
_suivant = 0;
|
|
}
|
|
}
|
|
|
|
~Noeud() {
|
|
delete _suivant;
|
|
}
|
|
|
|
const T & getValeur() const {
|
|
return _valeur;
|
|
}
|
|
|
|
Noeud * getSuivant() const {
|
|
return _suivant;
|
|
}
|
|
|
|
void setSuivant(Noeud * suivant) {
|
|
_suivant = suivant;
|
|
}
|
|
|
|
bool aUnSuivant() const {
|
|
return _suivant != 0;
|
|
}
|
|
|
|
/**
|
|
* Methode recursive de suppression d'un element dans
|
|
* une liste chainee.
|
|
*
|
|
* @param liste une liste.
|
|
* @param x un element.
|
|
*
|
|
* @return le liste sans l'element.
|
|
*/
|
|
Noeud * retire(const T & x) {
|
|
|
|
Noeud * ret = this;
|
|
|
|
if (this->getValeur() == x) {
|
|
// On l'a trouve !
|
|
ret = this->getSuivant();
|
|
this->setSuivant(0);
|
|
delete this;
|
|
} else if (this->aUnSuivant()) {
|
|
// Il y a un suivant.
|
|
this->setSuivant(this->getSuivant()->retire(x));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Concept d'iterateur d'une liste.
|
|
*/
|
|
|
|
class Iterateur {
|
|
|
|
public:
|
|
/**
|
|
* Constructeur d'iterateur. L'iterateur retourne permet
|
|
* d'acceder au premier element de la l'ensemble.
|
|
*
|
|
* @param e l'enemble sur lequel l'iterateur s'applique
|
|
*/
|
|
Iterateur(const Ensemble<T> & e) : _ensemble(e) {
|
|
_noeudSuivant = e._liste;
|
|
}
|
|
|
|
/**
|
|
* Test la fin de l'ensemble itere
|
|
*
|
|
* @return true si il reste des element, false sinon
|
|
*/
|
|
bool hasNext() const {
|
|
return _noeudSuivant != 0;
|
|
}
|
|
|
|
/**
|
|
* @return l'element courant et passe au suivant
|
|
*/
|
|
const T & next() {
|
|
const T & v = _noeudSuivant->getValeur();
|
|
|
|
_noeudSuivant = _noeudSuivant->getSuivant();
|
|
|
|
return v;
|
|
}
|
|
|
|
private:
|
|
/**
|
|
* l'enemble itere
|
|
*/
|
|
const Ensemble<T> & _ensemble;
|
|
|
|
/**
|
|
* la position courante dans l'ensemble
|
|
*/
|
|
Noeud * _noeudSuivant;
|
|
};
|
|
|
|
Noeud * _liste;
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
* Construit un ensemble vide.
|
|
*/
|
|
Ensemble<T>() : _liste(0) { }
|
|
|
|
/**
|
|
* Construit un singleton.
|
|
*/
|
|
Ensemble<T>(T x) {
|
|
_liste = new Noeud(x);
|
|
}
|
|
|
|
/**
|
|
* Destructeur.
|
|
*/
|
|
~Ensemble<T>() {
|
|
// delete 0 fonctionne !
|
|
delete _liste;
|
|
_liste = 0;
|
|
}
|
|
|
|
/**
|
|
* Test si l'ensemble est vide.
|
|
*
|
|
* @return true si l'ensemble est vide, sinon false.
|
|
*/
|
|
bool estVide() const {
|
|
return _liste == 0;
|
|
}
|
|
|
|
/**
|
|
* Envoie tous les elements dans un flot de sortie.
|
|
*
|
|
* @param out un flot de sortie.
|
|
*
|
|
* @return le flot de sortie donne en parametre.
|
|
*/
|
|
std::ostream & flush(std::ostream & out) const {
|
|
Noeud * courant = _liste;
|
|
|
|
out << "[ ";
|
|
|
|
while (courant != 0) {
|
|
out << courant->getValeur() << " ";
|
|
courant = courant->getSuivant();
|
|
}
|
|
|
|
out << "]" << std::endl;
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Test l'appartenance d'un element a l'ensemble.
|
|
*
|
|
* @param x un double.
|
|
*
|
|
* @return true sie est dans l'ensemble, false sinon.
|
|
*/
|
|
bool contient(const T & x) const {
|
|
Noeud * courant = _liste;
|
|
bool result = false;
|
|
|
|
while (courant != 0) {
|
|
if (courant->getValeur() == x) {
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
courant = courant->getSuivant();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Test l'inclusion dans un autre ensemble.
|
|
*
|
|
* @param e un ensemble
|
|
*
|
|
* @return true si "je" suis inclus dans e, false sinon.
|
|
*/
|
|
bool estInclusDans(const Ensemble<T> & autre) const {
|
|
Noeud * courant = _liste;
|
|
bool result = true;
|
|
|
|
while (courant != 0) {
|
|
if (!autre.contient(courant->getValeur())) {
|
|
result = false;
|
|
break;
|
|
}
|
|
|
|
courant = courant->getSuivant();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Ajoute un "objet" a l'ensemble.
|
|
*
|
|
* @param x un element a ajouter a l'ensemble.
|
|
*/
|
|
void ajoute(const T & x) {
|
|
if (!this->contient(x)) {
|
|
_liste = new Noeud(x, _liste);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retire un element de l'esemble.
|
|
*
|
|
* @param e un element a retirer.
|
|
*/
|
|
void retire(const T & e) {
|
|
_liste = _liste->retire(e);
|
|
}
|
|
|
|
|
|
/**
|
|
* Ajoute tous les elements dans un autre ensemble.
|
|
*
|
|
* @param e un ensemble
|
|
*/
|
|
void ajouteDans(Ensemble<T> & e) const {
|
|
Noeud * courant = _liste;
|
|
|
|
while (courant != 0) {
|
|
e.ajoute(courant->getValeur());
|
|
|
|
courant = courant->getSuivant();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retire tous les elements dans un autre ensemble.
|
|
* Apres a.enleveDe(b), b vaut b - a (- ensembliste)
|
|
*
|
|
* @param e un ensemble dont il faut retirer des elements.
|
|
*/
|
|
void retireDe(Ensemble<T> & e) const {
|
|
Noeud * courant = _liste;
|
|
|
|
while (courant != 0) {
|
|
e.retire(courant->getValeur());
|
|
courant = courant->getSuivant();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Constructeur par recopie.
|
|
*
|
|
* @param e un ensemble
|
|
*/
|
|
Ensemble(const Ensemble<T> & e) {
|
|
if (!e.estVide()) {
|
|
this->_liste = new Noeud(*(e._liste));
|
|
} else {
|
|
this->_liste = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Operateur d'affectation d'un ensemble.
|
|
*
|
|
* @param e un ensemble
|
|
*
|
|
* @return une reference a moi-meme
|
|
*/
|
|
Ensemble<T> & operator=(const Ensemble<T> & e) {
|
|
if (&e != this) {
|
|
delete this->_liste;
|
|
|
|
// nous nous voyons ici dans l'obligation de recopier
|
|
// le contenu du constructeur de recopie, ne pouvant
|
|
// l'appeler directement.
|
|
this->_liste = new Noeud(*(e._liste));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Creation d'un singleton.
|
|
*
|
|
* @param x un element
|
|
*
|
|
* @return le singleton {x}
|
|
*/
|
|
static Ensemble<T> singleton(T x) {
|
|
return Ensemble<T>(x);
|
|
}
|
|
|
|
/**
|
|
* Creation d'un ensemble vide.
|
|
*
|
|
* @param x un double
|
|
*
|
|
* @return le singleton {x}
|
|
*/
|
|
static Ensemble<T> ensembleVide() {
|
|
return Ensemble<T>();
|
|
}
|
|
|
|
/**
|
|
* Retourne un iterateur.
|
|
*
|
|
* @return un ipointeur sur un iterateur.
|
|
*/
|
|
Iterateur * getIterateur() const {
|
|
return new Iterateur(*this);
|
|
}
|
|
|
|
|
|
/**
|
|
* Application d'une fonction a tous les elements d'un ensemble
|
|
*
|
|
* @param fct le foncteur
|
|
* @return copie le nouvel ensemble contenant les resultat en valeur de retour
|
|
*/
|
|
Ensemble<T> appliquerAuxElements(Foncteur<T> & fct) const {
|
|
Ensemble<T> dest;
|
|
Iterateur * it = this->getIterateur();
|
|
|
|
while (it->hasNext()) {
|
|
dest.ajoute(fct(it->next()));
|
|
}
|
|
|
|
delete it;
|
|
|
|
return dest;
|
|
}
|
|
|
|
private:
|
|
|
|
/* Noeud * retireRec(Noeud * liste, T x);
|
|
*
|
|
* NOTE :
|
|
* Cette fonction n'utilisant, ni variable d'instance, ni methode de cette
|
|
* classe, nous avon juge bon de deplacer cette fonction utilitaire dans la
|
|
* classe Noeud ou elle devient une methode d'instance a part entiere.
|
|
*/
|
|
|
|
|
|
};
|
|
|
|
|
|
/**
|
|
* Operateur << pour les ensembles.
|
|
*
|
|
* @param out un flot de sortie.
|
|
* @param e un ensemble.
|
|
*
|
|
* @return le flot de sortie donne en argument.
|
|
*/
|
|
template <typename T>
|
|
std::ostream & operator<<(std::ostream & out, const Ensemble<T> & e) {
|
|
return e.flush(out);
|
|
}
|
|
|
|
|
|
/*
|
|
* Creation d'un singleton.
|
|
*
|
|
* Note :
|
|
* Cette fonction utilitaire nous semble plus a sa place
|
|
* en tant que méthode statique la classe Ensemble
|
|
*
|
|
* @param x un element
|
|
*
|
|
* @return le singleton {x}
|
|
*/
|
|
//template<typename T> Ensemble<T> singleton(T x);
|
|
|
|
/**
|
|
* Creation d'un ensemble vide.
|
|
*
|
|
* Note :
|
|
* Cette fonction utilitaire nous semble plus a sa place
|
|
* en tant que méthode statique la classe Ensemble
|
|
*
|
|
* @param x un double
|
|
*
|
|
* @return le singleton {x}
|
|
*/
|
|
//template<typename T> Ensemble<T> ensembleVide();
|
|
|
|
/**
|
|
* Teste l'egalite de deux ensembles. Cette fonction (et les suivantes )
|
|
* serait aussi bien implemente en tant que methode membre, mais elle
|
|
* restera ici dans un but simplement didactique (syntaxe de la surcharge
|
|
* d'operateur hors classe et non acces a la partie privee afin d'utiliser
|
|
* les methodes publiques precedemment cites). On a egalite quand E1
|
|
* inclus dans E2 et E2 inclus dans E1
|
|
*
|
|
* @param a un ensemble.
|
|
* @param b un ensemble.
|
|
*
|
|
* @return true si a=b (i.e., a est inclus dans b et b est inclus dans a),
|
|
* sinon false.
|
|
*/
|
|
template <typename T>
|
|
bool egale(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return a.estInclusDans(b) && b.estInclusDans(a);
|
|
}
|
|
|
|
template <typename T>
|
|
bool operator==(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return egale(a, b);
|
|
}
|
|
|
|
|
|
/* ne voyons pas le sens de ces operateurs, dans le cas d'ensemble */
|
|
|
|
//template <typename T>
|
|
//bool operator<(const Ensemble<T> & a, const Ensemble<T> & b) {}
|
|
|
|
//template <typename T>
|
|
//bool operator>(const Ensemble<T> & a, const Ensemble<T> & b) {}
|
|
|
|
|
|
/**
|
|
* Union de deux ensembles de doubles.
|
|
*
|
|
* @param a un ensemble de doubles.
|
|
* @param b un ensemble de doubles.
|
|
*
|
|
* @return a new Ensemble c = a union b.
|
|
*/
|
|
template <typename T>
|
|
Ensemble<T> reunion(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
Ensemble<T> c(a);
|
|
b.ajouteDans(c);
|
|
return c;
|
|
}
|
|
|
|
template <typename T>
|
|
Ensemble<T> operator+(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return reunion(a, b);
|
|
}
|
|
|
|
template <typename T>
|
|
Ensemble<T> operator|(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return reunion(a, b);
|
|
}
|
|
|
|
|
|
/**
|
|
* Difference de deux ensembles.
|
|
*
|
|
* @param a un ensemble de doubles.
|
|
* @param b un ensemble de doubles.
|
|
*
|
|
* @return a new Ensemble a prive de b.
|
|
*/
|
|
template <typename T>
|
|
Ensemble<T> difference(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
Ensemble<T> c(a);
|
|
b.retireDe(c);
|
|
return c;
|
|
}
|
|
|
|
template <typename T>
|
|
Ensemble<T> operator-(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return difference(a, b);
|
|
}
|
|
|
|
|
|
/**
|
|
* Difference symetrique entre deux ensembles.
|
|
*
|
|
* @param a un ensemble.
|
|
* @param b un ensemble.
|
|
*
|
|
* @return (a prive de b) union (b prive de a)
|
|
*/
|
|
template <typename T>
|
|
Ensemble<T> diffSymetrique(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return (a - b) + (b - a);
|
|
}
|
|
|
|
template <typename T>
|
|
Ensemble<T> operator^(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return diffSymetrique(a, b);
|
|
}
|
|
|
|
|
|
/**
|
|
* Intersection entre deux ensembles de doubles.
|
|
*
|
|
* @param a un ensemble de doubles.
|
|
* @param b un ensemble de doubles.
|
|
*
|
|
* @return l'intersection de a et b.
|
|
*/
|
|
template <typename T>
|
|
Ensemble<T> intersection(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return (a + b) - (a ^ b);
|
|
}
|
|
|
|
template <typename T>
|
|
Ensemble<T> operator&(const Ensemble<T> & a, const Ensemble<T> & b) {
|
|
return intersection(a, b);
|
|
}
|
|
|
|
|
|
#endif /* ENSEMBLE_H */
|
|
|
|
|