class - DCanL

Transcription

class - DCanL
Département Informatique
Programmation objet
Cours n°6
Structures de données – partie 2
Conteneurs évolués C++
algorithmes génériques
1
Département Informatique
Le conteneur std::set<>
Souvent nous avons besoin d'une structure de donnée représentant
un ensemble d'éléments, non ordonnés.
Ni une liste, ni un tableau, ne représentent correctement ces notions.
Leur structure fait que la recherche par valeur est pénalisante.
La classe std::set<>représente un ensemble de données non
ordonnées, pour laquelle la recherche par la valeur est optimisée.
La valeur n'est présente qu'une seule fois dans le conteneur.
2
Département Informatique
Opérations standard sur un std::set<T>
• insert(T)
• erase(i), i étant un std::set<T>::iterator
• find(T)
• begin(), end(), etc... comme toute collection C++
• Empty()
• count(T)
• etc...
std::set<>contient une classe iterator qui permet de parcourir le
conteneur. L'ordre utilisé est celui fourni par l'opérateur < (sauf si un
autre opérateur de comparaison est fourni, voir predicats)
3
Département Informatique
Exemple d'utilisation d'un std::set<>
std::set< char > Voyelles;
Voyelles.insert('A'); Voyelles.insert('E');
Voyelles.insert('O'); Voyelles.insert('I');
Voyelles.insert('U');
std::cout<< Voyelles.size() << " voyelles.";
char c;
do {
std::cin>>c;
if(Voyelles.count(c)>0)
std::cout<<c<<" est une voyelle";
}
while(c!='\n');
4
Département Informatique
Conteneur std::multiset<>
Ce conteneur est très proche de std::set<>, mais il supporte plusieurs
occurrences de la même valeur.
Son fonctionnement est très proche, il possède les mêmes opérations.
5
Département Informatique
Conteneur associatif std::map<>
Quand les données à stocker sont organisées à l'aide d'une clef, les
conteneurs usuels (tableau, liste, etc...) ne sont pas adaptés.
L'utilisation du conteneur std::map<>permet d'avoir un stockage
des éléments en tenant compte d'une clé qui n'est pas forcément la
position (comme dans vector)
template <class key, class value> class map {};
std::map<>garantit une recherche rapide dans la « table » lorsqu'on
fournit la clé.
std::map<int, T> ressemble à std::vector<T>
6
Département Informatique
Opérations standard
• operator[] (key)pour lire/écrire/insérer des valeurs
• find(T)
• count(T)
• empty(), size()
• clear(), erase()
• begin(), end()
std::map<>contient une classe iterator pour parcourir la collection.
L'itérateur référence un objet std::pair<T1,T2>défini comme :
template <class T1, class T2> struct pair
{
T1 first;
T2 second;
};
7
Département Informatique
Exemple d'utilisation de std::map<>
using namespace std;
map< string, string> Repertoire;
Repertoire["guidet"] = "
[email protected]";
Repertoire["nicolle"] = "
[email protected]";
for(map<string,string>::iterator i=Repertoire.begin(
i!=Repertoire.end(); ++i)
{
cout<<"Nom :"<<i->first;
cout<<"\tMail :"<<i->second;
}
if(Repertoire.count("cruz")==0)
cout<<"Mail de christophe cruz introuvable !";
8
Département Informatique
Le conteneur std::multimap<>
Permet d'avoir plusieurs valeurs pour chaque « clé »
Les opérations sont identiques à la map, sauf l'opérateur
[] qui n'est pas défini.
9
Département Informatique
Utilisation avancée des conteneurs standard
Une utilisation fréquente des modèles C++ est le développement
de conteneurs.
Mais un algorithme peut éalement profiter du polymorphisme
de généricité, si un traitement est générique et doit être passé
en paramètre.
Un tel type (traitement générique) est appelé objet foncteur.
10
Département Informatique
Exemple de prédicat
Un prédicat est une fonction booléenne, représentant une
condition à satisfaire.
Imaginons par exemple que l'on veuille afficher tous les éléments
d'un tableau (type std::vector) dont les éléments sont inférieurs à
un élément donné.
Le code ressemblerait à :
for(int i=0; i<Tableau.size(); i++)
{
Et si on veut changer
if( Tableau[i] < ValeurDonnee) la condition, il faut
std::cout<<Tableau[i];
changer le code !!!
}
11
Département Informatique
Solution : utiliser un prédicat.
template <class predicat>
void AfficheSi(const std::vector<int>& V, predicat f)
{
for(int i=0;i<V.size();i++)
if( f(V[i]) )
Ceci peut être une fonction,
std::cout<<V[i];
ou un objet foncteur
}
Le code est plus générique, mais limité à un tableau de int...
12
Département Informatique
template <class predicat, class elt>
void AfficheSi(const std::vector<elt>& V, predicat f
{
for(int i=0;i<V.size();i++)
if( f(V[i]) )
std::cout<<V[i];
}
C'est mieux, mais encore limité aux tableaux... Alors qu'on pourrait
imaginer utiliser d'autres conteneurs (comme std::list...). Profitons de
l'interface commune des conteneurs standards (les iterateurs) pour
généraliser un peu plus...
13
Département Informatique
template <class predicat, class iterator>
void AfficheSi(iterator debut, iterator fin
, predicat f)
{
for(iterator i=debut; i!=fin; ++i)
if( f(*i) )
std::cout<< *i;
}
A présent le code peut s'utiliser pour afficher tous les éléments d'une liste
d'entiers différents de -5, tous les éléments d'un tableau de chaînes de moins
de trois caractères, etc..., à condition d'écrire le prédicat.
14
Département Informatique
Afficher les éléments d'une std::list<std::string> de 3 caractères
bool Moins3Car(const std::string& str)
{
return str.length() == 3;
}
std::list<std::string> Liste;
AfficheSi(Liste.begin(), Liste.end(), Moins3Car );
15
Département Informatique
Afficher les éléments d'un vecteur d'entiers supérieurs à un seuil
class SupSeuil
{
int Seuil;
public:
SupSeuil(int s):Seuil(s){}
bool operator() (int val) const
{
return val>Seuil;
}
};
std::vector<int> V;
int Seuil; std::cin>>Seuil;
AfficheSi(V.begin(), V.end(), SupSeuil(Seuil) );
16
Département Informatique
On pourrait imaginer d'autres utilisation possibles de cette fonction
AfficheSi, que l'on peut appeler un algorithme générique.
La bibliothèque standard fournit une grande quantité d'algorithmes
de ce type, construits de la même manière, avec une très grande
généricité. (en-tête : <algorithm> )
Citons entre autres :
for_each : Effectue une action non modifiante sur tous les éléments
transform : Effectue une action modifiante sur tous les éléments
find
: effectue une recherche sur tous les éléments...
find_if
: effectue une recherche en utilisant un prédicat
max_element : retrouve le plus grand élément d'une collection
sort
: trie une collection
17
Département Informatique
Il est donc conseillé, si l'un souhaite réaliser un traitement généralisable,
d'écrire une algorithme générique.
Il est également conseillé, si l'on souhaite effectuer un traitement sur
un ensemble, d'utiliser un algorithme standard.
La bibliothèque standard fournit également des prédicats, ainsi que
d'autres objets foncteurs usuels. (en-tête <functional>)
less<>
plus<>
: encapsule l'opérateur <
: encapsule l'opérateur +
18
Département Informatique
Exemple : afficher tous les éléments d'une collection...
template <class elt>
class SortieSurFlux
{
std::ostream& flux;
char Separator;
public:
SortieSurFlux(std::ostream& f,char sep='\n')
:flux(f), Separator(sep){}
void operator()(const elt& e) {
flux<<e<<Separator; }
};
std::list<std::string> L;
std::for_each(L.begin(), L.end(),
SortieSurFlux(std::cout,'-') );
19
Département Informatique
Exemple : complémenter tous les éléments d'un vector<bool>
std::vector<bool> V1, V2;
//....
std::transform( V1.begin(), V1.end(),
V2.begin(), std::logical_not<
bool>() );
Exemple :
créer une liste d'entiers résultante de la somme de 2 listes d'entiers
std::list<int> L1, L2, L3;
//...
std::transform( L1.begin(), L1.end(),
L2.begin(), L3.begin(), std::plus<
int>());
20
Département Informatique
Prochain cours :
Structures de données – partie 3
arbres binaires de recherche
algorithmes de base
A la semaine prochaine !
21