• Aucun résultat trouvé

Programmation objet

N/A
N/A
Protected

Academic year: 2022

Partager "Programmation objet"

Copied!
21
0
0

Texte intégral

(1)

Département Informatique Département Informatique

Structures de données – partie 2 Conteneurs évolués C++

algorithmes génériques

Programmation objet

Cours n°6

(2)

Département Informatique 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.

(3)

Département Informatique 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)

(4)

Département Informatique

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');

(5)

Département Informatique

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.

(6)

Département Informatique

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>

(7)

Département Informatique

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;

(8)

Département Informatique

Département Informatique Exemple d'utilisation de std::map<>

using namespace std;

map< string, string> Repertoire;

Repertoire["guidet"] = "guidet@u-bourgogne.fr";

Repertoire["nicolle"] = "nicolle@u-bourgogne.fr";

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 !";

(9)

Département Informatique

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.

(10)

Département Informatique

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.

(11)

Département Informatique 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é.

for(int i=0; i<Tableau.size(); i++) {

if( Tableau[i] < ValeurDonnee) std::cout<<Tableau[i];

}

Et si on veut changer la condition, il faut changer le code !!!

Le code ressemblerait à :

(12)

Département Informatique 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]) )

std::cout<<V[i];

}

Le code est plus générique, mais limité à un tableau de int...

Ceci peut être une fonction, ou un objet foncteur

(13)

Département Informatique 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...

(14)

Département Informatique 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.

(15)

Département Informatique 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 );

(16)

Département Informatique 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) );

(17)

Département Informatique 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

(18)

Département Informatique 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<> : encapsule l'opérateur <

plus<> : encapsule l'opérateur +

(19)

Département Informatique 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(),

(20)

Département Informatique 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>());

(21)

Département Informatique Département Informatique

Prochain cours :

Structures de données – partie 3

arbres binaires de recherche algorithmes de base

A la semaine prochaine !

Références

Documents relatifs

Seuls les tests complémentaires pertinents pour votre race sont inclus - liste par race ci-dessous.. Le Locus I (Intensité de la Phéomélanine) est inclus pour

Tous les éléments graphiques doivent être dimensionnés et positionnés à l'aide d'une cotation directe qui doit apparaître et rester sur les esquisses.. Ci contre: tous les

On doit tirer h n h éléments de la commune (i) sortie h fois ; mais on ne peut obtenir h n { éléments tous distincts que si le nombre maximum de billets que l'on risque de

3.1) Soit un entier p premier avec 10 (son chiffre des unités est 1, 3, 7 ou 9). Il admet un multiple où les chiffres 0 et 1 alternent. Son chiffre des unités est impair ; je

A contrario, un entier est dit « déséquilibré » s’il existe au moins deux chiffres consécutifs de sa représentation décimale qui ont la même parité, par exemple 8878311.

En C++, les chaînes de caractères sont stockées dans des variables de type string : string prenom = &#34;Robert&#34;; // string pour les chaînes de caractères.. Les chaînes

L’exemple ci-dessous est une liste chaînée dont chaque élément est constitué d’une donnée entière et d’un pointeur vers un autre élément de même type. Cependant,

Pour bien faire comptez au moins 24 heures de “marinage” au frais en retournant la viandes toutes les 3 ou 4 heures pour qu’elle soit bien “imbibée” : c’est indispensable