La présentation est en train de télécharger. S'il vous plaît, attendez

La présentation est en train de télécharger. S'il vous plaît, attendez

Structures de données IFT-2000 Abder Alikacem Standard Template library Édition Septembre 2009 Département dinformatique et de génie logiciel.

Présentations similaires


Présentation au sujet: "Structures de données IFT-2000 Abder Alikacem Standard Template library Édition Septembre 2009 Département dinformatique et de génie logiciel."— Transcription de la présentation:

1 Structures de données IFT-2000 Abder Alikacem Standard Template library Édition Septembre 2009 Département dinformatique et de génie logiciel

2 Plan Description générale Conteneurs Conteneurs séquentiels Vector, list, deque Conteneurs associatifs Set, map Adaptateurs Stack, queue Itérateurs Algorithmes Foncteurs Adaptateurs de fonctions

3 STL : Standard Template Library La STL est une bibliothèque de C++ qui permet de mettre en œuvre dautres structures de données plus complexes et de faciliter également lécriture de programmes. En quelques sortes, cette bibliothèque propose des algorithmes clés en main pour beaucoup de problèmes de programmation. Étant donné la complexité des programmes écrits en C++, à chaque fois que cela est possible, il recommandé dutiliser des STL. Facteurs de qualité des logiciels : Fiabilité : écrite par des spécialistes (Andrew Koenig) Réutilisabilité : portabilité Compréhensabilité et facilité de maintenance => EFFICACITE

4 Exemple : Fusionner deux listes en les triant et placer le résultat dans un fichier se code en deux lignes. Développer rapidement des applications en assemblant des briques des classes génériques. STL : Standard Template Library

5 Il sagit donc dune bibliothèque générique qui fournit des solutions pour gérer un ensemble de données en utilisant des algorithmes efficaces. Du point de vue du programmeur, STL fournit un groupe de classes répondant à divers besoins. Tous les composants de STL sont des templates Une STL est développée selon les axes suivants : conteneurs – itérateurs - algorithmes

6 STL : Standard Template Library Il existe deux grandes catégories de conteneurs : Les séquences élémentaires (appelées aussi stockages élémentaires). Les dérivées des séquences élémentaires (appelées aussi types abstraits de données : TDA) Les conteneurs associatifs (clé,valeur) Pour comprendre les conteneurs proposés dans la STL, on doit donc appréhender à la fois les structures de données, les algorithmes associés et les itérateurs. http://www.sgi.com/tech/stl/

7 STL : Standard Template Library Conteneurs: En C++, une classe contenant un ensemble déléments d'un certain type est appelée conteneur. Ce sont donc eux qui contiendront les informations que lon veut stocker. Itérateurs: utilisés pour parcourir les items qui se retrouvent dans les conteneurs, ils jouent un peu le rôle de pointeurs sur des éléments dun conteneur. Algorithmes: utilisés pour faire des traitements sur les éléments qui se retrouvent dans les conteneurs.

8 STL : Standard Template Library Les algorithmes sont indépendants du type de données stockées. Il sagit ainsi de connecter des algorithmes à des structures de données, par le biais de connecteurs.

9 Les conteneurs Les conteneurs contiennent les structures de données linéaires telles que les listes, piles, tables, etc, utilisées pour stocker des données. Lutilisation des templates dans une STL permet ladaptation à tous les types de données. Les conteneurs les plus utilisés sont : vector Tableau list Liste doublement chaînée slist List simplement chaînée queue File- FIFO (first-in, first-out) deque Tableau avec des opération efficaces dinsertion et de suppression aux extrémités set Ensemble avec des éléments distincts stack Pile - LIFO (last in, first out) map Table de hachage multiset Comme lensemble mais autorise des valeurs répétées multimap Comme la table mais autorise des clefs multiples

10 Les méthodes des conteneurs push_front Insère un élément avant le premier (non disponible pour vector) pop_front Supprime le premier élément (non disponible pour vector) push_back Insère élément après le dernier pop_back Supprime le dernier élément empty Booléen indiquant si le conteneur est vide size Retourne le nombre déléments du conteneur insert Insère un élément à une position donnée erase Supprime un élément à une position donnée clear Supprime tous les éléments resize Redonne une taille au conteneur front Retourne ladresse du premier élément back Retourne ladresse du dernier élément remove Supprime le premier élément (non disponible pour vector) sortTrier reverseOrdre inverse findTrouver un élément swapéchange deux éléments de deux vecteurs

11 Les conteneurs Les conteneurs sont classés suivant deux types: séquentiels: les éléments sont ordonnés et leurs positions sont indépendantes des caractéristiques des éléments eux-mêmes associatifs: les éléments sont triés selon un certain critère; la position dun élément est un endroit identifié par un « nom » et peut dépendre de la valeur de lélément

12 Conteneurs séquentiels vector: tableau dynamique qui ne se remplit quà la fin deque: tableau dynamique qui peut sétendre par les deux extrémités list: liste doublement chaînée on verra plus loin que les piles et les files sont définies en fonction des ces trois conteneurs Une séquence est un conteneur dans lequel les éléments sont organisés linéairement (il y a un premier, un suivant …, un dernier). On distingue trois séquences:

13 Les vecteurs (vector) Les conteneurs vector et deque fournissent laccès aux éléments à travers lindexation [ ]. Ceci permet un accès direct à un élément par le biais dun indice. Les vecteurs font référence aux tableaux dynamiques. Les éléments sont insérés à la fin du tableau. La déclaration vector unEnsemble; crée un tableau dentiers. Dans ce cas, le constructeur par défaut nous retourne un tableau vide. Les méthodes les plus importantes sont : - size( ) ; empty( ) ; clear( ) ; resize( ) ; - front( ) ; back( ) ; -push_front(valeur); push_back(valeur); -pop_front( ); pop_back( ); Les opérateurs les plus utilisées sont : =, = =, <, [ ]. Avantages : ajout/suppression à la fin en O(1) ; accès direct aux éléments en O(1). Inconvénients : lajout et la suppression est O(n) en général.

14 Les vecteurs (vector) Les vecteurs sont donc des listes implémentées à l'aide de tableaux. Ils remplacent avantageusement les tableaux standards du C car leur taille est implicite et peut être redéfinie. De plus, on peut affecter un vecteur dans un autre à l'aide de l'opérateur d'affectation. On peut définir un vecteur d'entiers de la façon suivante: vector monvecteur(100); Linsertion dun élément à la fin est très rapide (sauf dans certains cas que lon verra plus loin) Linsertion au milieu est très lente parce quelle exige un déplacement de tous les éléments qui sont stockés après la position dinsertion

15 Les vecteurs (vector) Exemple 1 vector v(3); // Déclarstion dun vector de 3 éléments. v[0] = 7; v[1] = v[0] + 3; v[2] = v[0] + v[1]; // v[0] == 7, v[1] == 10, v[2] == 17 reverse(v.begin(), v.end()); // v[0] == 17, v[1] == 10, v[2] == 7

16 Les vecteurs (vector) Exemple 2 int main() { vector unTableau; for (int i = 1; i < 10; ++i) { unTableau.push_back(i); } for (int j = 0; j < unTableau.size(); ++j) { cout << unTableau[j] << ' '; } cout << endl; return 0; }

17 Les vecteurs (vector) Exemple 3 #include using namespace std; int main ( ) { vector vect1, vec2(3); vec1.push_back(10) ; vec1.push_back(12) ; vec1.push_back(20) ; vec2[0] = 1; vec2[2] = 10; vec2[3] = 20; cout << Les deux vecteurs cout << (vec1 != vec2 ? sont différents : sont identiques ) ; return 0 ; }

18 Les vecteurs (vector) Exemple 4 # include # include using namespace std; int main (void) { vector v; V1.push_back(1); V1.push_back(2); V1.push_back(3); vector v2(3); v2[0] = 1, v2[1] = 2; v2[2] =3; if (v1==v2) cout << " OK " ; else cout << " ???? (stupeur) "; return 0; }

19 Les vecteurs (vector) Exemple 5 Un tableau à deux dimensions est un vecteur de vecteurs. Le constructeur de vecteurs peut initialiser la taille du tableau et aussi la valeur initiale. #include using namespace std; int main(){ // Déclarer un tableau à deux dimensions et initialiser à 0 vector > vI2Matrix(3, vector (2,0)); vI2Matrix[0][0] = 0; vI2Matrix[0][1] = 1; vI2Matrix[1][0] = 10; vI2Matrix[1][1] = 11; vI2Matrix[2][0] = 20; vI2Matrix[2][1] = 21; cout << "Itérer par indice:" << endl; for(int ii=0; ii < 3; ii++) { for(int jj=0; jj < 2; jj++) { cout << vI2Matrix[ii][jj] << endl; } return 0; }

20 Les vecteurs (vector) FonctionDescription vector v; Déclaration dun Vector de type "T". vector v(size_type n); Déclaration dun Vector de type "T" et de taille "n". vector v(size_type n,const T& t); Déclaration dun Vector de type "T" et de taille "n" contenant la valeur "t".

21 Les vecteurs (vector) Exemple 6 #include #include using namespace std; int main(){ // Vecteur de 3 éléments initialisé à 0 vector vI1Matrix(3,0); // Vecteur de 4 éléments contenant chacun un autre vecteur // vecteur vI1Matrix qui a été initialisé à 0 vector > vI2Matrix(4, vI1Matrix); // Vecteur 5 éléments contenant chaucn un vecteur de dimension deux vector > > vI3Matrix(5, vI2Matrix); //Ou alors si on veut en une seule déclaration : //vector > > vI3Matrix(2, vector > (3, vector (4,0)) ); for(int kk=0; kk<4; kk++) { for(int jj=0; jj<3; jj++) { for(int ii=0; ii<2; ii++) { cout << vI3Matrix[ii][jj][kk] << endl; } } return 0; }

22 Les vecteurs – Taille et capacité Il est important de distinguer la taille et la capacité dun vector car il maintient à linterne un tableau qui nest pas nécessairement rempli Taille: nombre déléments effectivement contenus dans le tableau interne Capacité: taille du tableau interne. Elle est augmentée lorsquon veut insérer un nouvel item et que le tableau est plein

23 Les vecteurs – Capacité Initialement la capacité est 0 Aussitôt quon ajoute un premier élément, on alloue un tableau de taille 1 (capacité = 1) Lorsque la capacité est réajustée, il faut allouer un nouveau tableau et copier les éléments dans ce nouveau tableau La réallocation est donc coûteuse On peut fixer la capacité du vecteur: vector unTableau; unTableau.reserve(10); Il est important de noter que la réallocation invalide tout pointeur, référence ou itérateur sur des éléments du vector avant réallocation

24 Les vecteurs – Capacité Dans la plupart des implémentations, la capacité est doublée chaque fois quelle doit être augmentée Dans.NET on ajoute un nombre de cellules qui croît à chaque réallocation selon la suite de Fibonacci Dans tous les cas, le principe est le même: plus le tableau est grand, plus il sera agrandi lors dun réallocation Pourquoi? Tout simplement parce plus il est grand, plus lallocation coûte cher (beaucoup déléments à recopier). On veut donc diminuer le nombre de ces réallocations. Bien sûr, cela a pour effet de causer une éventuelle sur-utilisation de mémoire

25 Les vecteurs – Capacité int main() { vector unTableau; cout << "capacite initiale: " << unTableau.capacity() << endl; for (int i = 1; i < 10; ++i) { unTableau.push_back(i); cout << "capacite: " << unTableau.capacity() << endl; } for (int j = 0; j < unTableau.size(); ++j) { cout << unTableau[j] << ' '; } cout << endl; return 0; } Exemple 7

26 Les vecteurs Principales opérations (n est la dimension du vecteur) Ajout ou suppression d un élément en fin de vecteur sans redimensionnement0(1) push_back Ajout ou suppression d un élément en fin de vecteur avec redimensionnement0(n) push_back Ajout ou suppression d un élément au milieu du vecteur 0(n)

27 Les listes (list) Liste doublement chaînée Un élément pointe sur son prédécesseur et son successeur Les listes sont des séquences ordonnées déléments d'un certain type. Elles sont implémentées à l'aide de listes doublement chaînées: On peut définir une liste de 100 entiers de la façon suivante: list maliste(100);

28 Les listes (list) Les méthodes les plus importantes sont : - size( ) ; empty( ) ; clear( ) ; resize( ) ; - front( ) ; back( ) ; - push_fron(valeur); push_back(valeur); -pop_front( ); pop_back( ); remove (valeur); Avantages : ajout/suppression se font en O(1) Inconvénients : laccès aux éléments se fait en O(n).

29 Les listes (list) - Caractéristiques Pas daccès direct à un élément au milieu de la liste On peut insérer ou retirer un élément nimporte où à un coût constant Linsertion ou le retrait délément ninvalidera jamais les pointeurs, références et itérateurs sur dautres éléments, comme cest le cas lors de réallocation avec les vectors et les deques

30 Les listes (list) - Caractéristiques Plusieurs fonctions pour déplacer, insérer ou retirer des éléments (efficaces parce quelle ne font que réaffecter des pointeurs) Exemples – unique() pour éliminer les duplications déléments consécutifs – reverse() beaucoup dautres

31 Les listes (list) Exemple 1 #include int main ( ) { list liste1 ; liste1.push_back(20) ; liste1.push_back(12) ; liste1.push_back(15) ; liste1.sort( ) ; liste1.reverse() ; cout << le début de liste est << liste1.front cout << la fin de liste est <<liste1.back ; return 0 ; } La liste utilisée ci-dessous est en fait doublement chaînée. Si on désire une liste simplement chaînée, remplacer list par slist.

32 Les listes (list) Exemple 2 int main() { list uneListe; for (char c = 'a'; c <= 'z'; ++c){ uneListe.push_back(c); } while (!uneListe.empty()){ cout << uneListe.front() << ' '; uneListe.pop_front(); } cout << endl; return 0; }

33 Les listes (list) Exemple 3 bool voyelle(char c) { return (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u'); }

34 Les listes (list) Exemple 3 suite int main() { list uneListe; for (char c='a'; c<='z'; ++c){ uneListe.push_back(c); } uneListe.remove_if(voyelle); uneListe.reverse(); while (!uneListe.empty()){ cout << uneListe.front() << ' '; uneListe.pop_front(); } cout << endl; return 0; }

35 Les listes (list) Exemple 4 #include using namespace std; list list1; // Ajoute des valeurs à la fin de la liste, initialement vide. // la fonction membre "push_back" ajoute un élément à la fin de la liste int value1 = 10; int value2 = -3; list1.push_back (value1); list1.push_back (value2); list1.push_back (5); list1.push_back (1); // Imprime les éléments de la liste Output cout << endl << "List values:" << endl; // Répéter aussi longtemps quil reste des éléments dans la liste while (list1.size() > 0) { int value = list1.front(); // Output la valeur the value. cout << value << endl; // Supprime lélément du début de la liste. list1.pop_front(); }

36 Les listes (list) Exemple 5 #include using namespace std; int main() { list l(4,0); // l vaut 0::0::0::0::[] vector v(10,1); // v vaut [1,1,1,1,1,1,1,1,1,1,1] vector ::iterator i =copy(l.begin(),l.end(),v.begin()); copy(v.begin(),i, ostream_iterator (cout," ")); copy(i,v.end(), ostream_iterator (cout," ")); return 0; }

37 Liste (list) et vecteur (vector) Fonctions communes à vector et list void push back(const Object& x):Ajoute x à la fin du conteneur. Notons que si un objet est ajouté à la fin d'un vecteur alors sa taille est automatiquement augmentée. void pop back(): Enlève le dernier objet du conteneur const Object& back() const: Retourne l'objet situé µa la fin du conteneur const Object& front() const: Retourne l'objet situé au début du conteneur Pour les conteneurs de type list seulement void push front(const Object& x): Ajoute x au début du conteneur void pop front(): Enlève le premier objet du conteneur Pour les conteneurs de type vector seulement Object& operator[] (int i): Retourne l'objet situé µa la position i du conteneur Object& at (int i): Comme le précédent mais avec un contrôle de la plage des valeurs. Déclenche une exception out of range lorsqu'un indice es tincorrect. void resize( int nouvelle taille): Redéfini la taille du conteneur int capacity() const: Retourne la capacité du conteneur void reserve(int nouvelle capacite): Redéfini la capacité du conteneu

38 Double end queue (deque) Tableau dynamique Peut sétendre dans les deux sens La fonction push_back() pour ajouter à la fin La fonction push_front() pour ajouter au début

39 Double end queue (deque) Une deque se comporte comme un vecteur à la différence que lajout et la suppression dune valeur au début de la structure se fait en O(1). Cette structure est intéressante dans le cas où les insertions et suppressions se font aux extrémités et où on a besoin dun accès efficace aux éléments. Les méthodes les plus importantes sont comme dans vector. Exemple: #include using namespace std; int main ( ) { deque DD1, DD2(3); DD1.push_back(1); DD1.push_back(2); DD1.push_back(3); DD2[0] =1; DD2[1]=2; DD2[3]=3; cout << "Deque " ; (DD1 == DD2) ? cout << "identiques" : cout <<"différents"; cout << endl; return 0 ; }

40 Deque - Implémentation Le tableau est divisé en blocs Le premier bloc sétend dans un direction et le dernier, dans lautre direction Lorsquun bloc est plein, on en crée un nouveau

41 Deque - Implémentation Premier élément Dernier élément

42 Deque - Caractéristiques Laccès est plus lent quavec un vecteur, parce quil faut dabord identifier le bloc, et ensuite la position dans le bloc Pas de fonction pour accéder ou fixer la capacité Un bloc peut être désalloué lorsque le deque diminue Pas besoin de recopier le tableau lorsquil y a réallocation Les itérateurs ne peuvent pas être des pointeurs ordinaires, puisquil faut parfois passer dun bloc à un autre Tout comme avec les vectors, linsertion ou la suppression déléments au milieu est très lente

43 STL - Les containeurs séquentiels Vector - extensible et relocalisable - accès aléatoire par index en O(1) - insertions et retraits à la fin en O(1) - insertions et retraits lents au milieu List ( liste circulaire doublement chaînée ) - insertions et retraits nimporte où en O(1) - accès au début et à la fin en O(1) - accès lent aux autres éléments Deque ( Double Ended Queue = tampon circulaire dynamique ) - exactement pareil que Vector pour la complexité - pas dinsertion au milieu - bon compromis vitesse daccès / souplesse du remplissage Synthèse

44 STL - Les containeurs séquentiels Synthèse Méthodes disponibles sur tout conteneur : Gestion de la taille du conteneur - size_type size() const; - size_type max_size() const; - bool empty() const; - void resize(size_type, T c=T()); Accès aux éléments : - const_reference front() const; - const_reference back() const;

45 STL - Les containeurs séquentiels Synthèse Méthodes disponibles sur tout conteneur : Insertion des éléments - void push_back(const T&); appel du constructeur par copie -... insert (...); avec un itérateur Suppression d éléments : - void pop_back(); -... erase (...); avec un itérateur Echange d éléments : - void swap(sequence &);

46 STL - Les containeurs séquentiels Synthèse Méthodes disponibles sur tout conteneur : Echange d éléments : - void swap(sequence &); Sequence est à remplacer par vector, list ou deque. Echange this avec les éléments du conteneur passé en argument. Pour échanger des éléments de séquences différentes, il faut passer à une version avec itérateur

47 Les séquences : types abstraits Les classes (conteneur) : - pile : stack - file d attente : queue - file d attente prioritaire : priority_queue A partir des séquences de base, on dérive trois types abstraits : pile, file d attente et file d attente prioritaire.

48 La pile (stack) Lattribut privé est un deque. Les méthodes les plus importantes sont : push(valeur), pop( ), top( ), empty() et size() #include using namespace std; int main() { stack EntStack; int Num; cout << "introduire un entier (ou CTRL z pour terminer): "; cin >> Num; while(!cin.fail()) { EntStack.push(Num); cout << "Introduire un entier (or CTRL z pour terminer): "; cin >> Num; } cout << endl << "Les nombres dans lordre inverse sont comme ci-dessous" << endl; while (!EntStack.empty()) { Num = EntStack.top(); EntStack.pop(); cout << Num << endl; } return 0; }

49 La file (queue) Cette structure dérive de deque, avec en plus les méthodes push(valeur) et pop( ).

50 Adaptateurs Uitilisé lorsquon veut redéfinir une interface pour une classe déjà existante On définit les méthodes de la nouvelle classe en fonction de celles de la classe de base On peut implémenter un adaptateur par agrégation, en utilisant comme attribut une instance de la classe de référence Exemple: la pile (stack) dans la bibliothèque STL

51 La Pile (stack) - Implémentation Voici comment la classe pourrait être implémentée: template class stack { public: stack(const deque & c = deque ()); bool empty() const { return cont.empty(); } size_type size() const { return cont.size(); } void push(const T & x) { cont.push_back(x); } void pop(){ cont.pop_back(); } T & top(){ return cont.back(); } const T & top(){ return cont.back(); } //... autres méthodes protected: deque cont; };

52 La Pile (stack) - Extension Remarquez que le conteneur caché dans la pile est déclaré protected On peut donc facilement étendre la classe Voici comment on peut y ajouter une méthode pour vider la pile: template class Pile : public stack { public: Pile() {} ~Pile() {} void vider() { while (!empty()) pop(); }; }

53 STL – Ladaptateur de conteneurs Pour résumer : Adaptateur > Stack ( la pile ) Peut être implémentée avec Vector, List, Deque Principe LIFO : push et pop à la même extrémité Queue ( la file ) Peut être implémentée avec List, Deque Principe FIFO Priority_queue ( la file par priorité ) Dépend dune fonction de comparaison: priority_queue, fcomp >

54 Conteneurs associatifs Contrairement aux séquences, les conteneurs associatifs peuvent identifier leurs éléments par la valeur d une clé. Cette clé a parfois pour valeur une partie de la valeur de l élément. Ces conteneurs sont particulièrement adaptés dans des applications où l on doit rechercher des éléments connaissant leur clé. Un conteneur associatif offre la possibilité de rechercher rapidement les éléments mémorisés par leur clé.

55 Conteneurs associatifs Ces conteneurs sont « paramétrés » avec le type de la clé correspondant.. Opérations sur les clés : recherche : find (complexité logarithmique) Comptage selon la clé : count On doit avoir une relation d ordre total sur les clés

56 Conteneurs associatifs Les éléments sont toujours ajoutés en respectant un ordre établi selon un critère précis Nous nous intéresserons à deux types de conteneur associatif: set: les éléments sont triés et ne peuvent apparaître quune seule fois map: les éléments sont des paires clé/valeur et sont triés en fonction de la clé; chaque clé ne peut apparaître quune seule fois Il existe des versions (multiset et multimap) qui permettent les répétitions

57 Ensembles (set) À moins dindication contraire, les éléments sont ordonnés en utilisant lopérateur < par défaut Il faut donc que cet opérateur soit défini pour le type dobjet qui est stocké dans le set Normalement implémenté en un arbre équilibré, ce fournit donc un algorithme efficace pour la rercherche dune valeur Nous savons que pour rechercher un élément dans un conteneur, il faut pouvoir tester légalité, or il nest pas nécessaire de définir lopérateur == pour lutilisation dun set La raison pour cela est que la comparaison dun élément x recherché est comparé avec un élément y du set de la manière suivante: if (! (x < y || y < x))

58 Ensembles (set) On suppose que chaque valeur de lensemble est unique. Les méthodes les plus importantes sont : -size ( ); empty ( ); -count(elem): retourne le nombre doccurrences de lélément dans le set (qui, évidemment, peut être supérieur à 1 seulement dans le cas dun multiset) -find(elem): retourne la position de la première occurrence de lélément dans le set (ou multiset) -insert(elem) : insère un nouvel élément et la valeur de retour dépend de si on a affaire à un set ou un multiset -erase(elem) : retire toutes les occurrences de lélément et retourne le nombre déléments retirés -clear() : vide le conteneur Les opérateurs les plus utilisés sont: =, = =, <, [ ]

59 Ensembles (set) La fonction insert(elem) retourne un objet du type suivant: pair Ceci représente une paire dont le premier item est un itérateur qui pointe à la position de lélément ajouté Le second item est true si linsertion a pû être effectuée (cest-à-dire que lélément nexistait pas déjà)

60 Ensembles (set) Contrainte importante: on ne peut pas modifier directement la valeur dun élément parce que cela pourrait affecter lordre: il faut dabord le retirer et ensuite le remplacer par un nouvel élément avec la nouvelle valeur. Pas daccès direct aux éléments, il faut utiliser des itérateurs. La complexité de toutes les opérations est en O(n) ; n étant le nombre déléments dans lensemble. Par ailleurs, en interne, les éléments sont tous rangés dans lordre croissant.

61 Ensembles (set) Exemple 1 #include using namespace std; int main( ) { set Ens; Ens.insert(10); Ens.insert(20); Ens.inser(14) ; Ens.erase(10) ; cout << le cardinal de lensemble Ens est << Ens.size() ; return 0 ; }

62 Ensembles (set) Exemple 2 #include set unEnsemble; unEnsemble.insert(3); unEnsemble.insert(1); unEnsemble.insert(5); unEnsemble.insert(4); unEnsemble.insert(1); unEnsemble.insert(6); unEnsemble.insert(2);

63 Dictionnaire (map) Les éléments sont une paire formée dune clé jumelée à une valeur Les éléments sont triés selon la clé Chacune des clés ne peut exister quune seule fois (mais peut être répétée dans un multimap) Contrairement aux sets, on peut accéder directement aux éléments #include map coll; coll["VAT"] = 0.15; // VAT est la clé coll["Pi"] = 3.1416; coll["an arbitrary number"] = 4983.223; coll["Null"] = 0;

64 Map - Caractéristique Lindice utilisé pour identifier un élément est la clé Le type dun élément de map est une paire pair où Key est le type de la clé, et T le type des items contenus dans le map Tout comme le set, le map fournit les méthodes count(clé) et find(clé) Attention: Si on accède en utilisant une clé pour laquelle il ny a aucun élément, un nouvel élément est automatiquement inséré avec cette clé, en utilisant le constructeur par défaut pour linitialiser

65 Map - Caractéristique On ne peut pas modifier une clé contenue dans le map, mais on peut modifier litem qui lui est associé Pour retirer un élément, il suffit dappeler la méthode erase(cle), qui élimine toutes ses occurrences et retourne le nombre déléments retirés Il existe aussi une méthode insert(elem), mais quon na pas besoin dutiliser en général (il est important de noter que elem dans ce cas est une paire qui contient une clé et son item associé) Ne pas oublier, lorsquon parcourt un map avec un itérateur, que celui-ci pointe sur une paire

66 Set et map La classe set peut être vu comme un cas particulier de la classe map où les deux composantes d'une paire sont identiques. On utilise un set lorsque la clef est la seule information qui nous intéresse. template class set { public: typedef Clef value_type; typedef Clef key_type; iterator begin(); iterator end(); iterator find(const key_type_type& k); pair insert(const value_type& val); void erase(iterator pos); int erase(const key_type& k); void clear(); // autres membres }; On remarque que la définition des classe set et map sont similaires. La principale différence est l'absence de l'opérateur d'indiçage dans la classe set. template class map { public: typedef Clef key_type; typedef Valeur mapped_type; typedef pair value_type; iterator begin(); iterator end(); mapped_type& operator[] (const key_type& k); iterator find(const key_type& k); pair insert(const value_type& val); void erase(iterator pos); int erase(const key_type& k); void clear(); // autres membres };

67 Multimap et multiset Les multimap et les multiset sont similaires aux classes map et set sauf que plusieurs éléments peuvent posséder la même clef. Les fonctions membres suivantes sont aussi disponibles pour les classes set et map mais sont surtout utiles pour les multiset et les multimap. iterator lower_bound(const key_type& k); iterator upper_bound(const key_type& k); pair equal_range(const key_type& k); La fonction lower(k) retourne un itérateur pointant sur le premier eléments possédant la clef k. La fonction upper(k) retourne un itérateur vers le premier élément dont la clef est supérieure à k. Dans les deux cas, si lélément recherché est inexistant, l'iterateur end() est retourné. Finalement, la fonction equal_range(const clef& k) retourne la paire d'itérateurs (lower(k), upper(k)).

68 Multimap et multiset L'exemple suivant illustre comment afficher de façon ordonnée tous les éléments de m possédant la clef s. void afficher(multimap & m, string s) { typedef multimap ::iterator MI; pair g=m.equal_range(s); for(MI p=g.first; p!=g.second; ++p) cout Elem<<endl; }

69 STL - Les containers associatifs Set ( liste triée ) - Chaque élément doit être unique ( pas de doublons ) - accès aléatoire par clé ( lobjet lui-même est la clé ) Multiset - Un set qui permet les doublons Map ( association clé / élément ) - une clé pour un élément ( pas de doublons ) - accès aléatoire par clé Mulimap - Un map ou les éléments peuvent être multiples pour une clé Synthèse

70 Conteneurs - Requis Lélément qui sera inclus dans un conteneur doit posséder: constructeur de recopie opérateur = destructeur possiblement, un constructeur par défaut possiblement, un test dégalité (opérateur ==) possiblement, un critère dordre (operateur < et autres)

71 Conteneurs – Remarques supplémentaires Tous les conteneurs ont un attribut size_type, qui est en fait un entier non signé pour représenter le nombre ditems dans le conteneur Tous les conteneurs ont aussi un attribut value_type, qui mémorise le type des entités quil contient

72 Les itérateurs Ils servent de lien entre les conteneurs et les algorithmes car permettant daccéder aux informations de la même manière. Un itérateur peut être vu comme un pointeur sur un élément dun conteneur. Par définition donc, un itérateur permet de récupérer une donnée pour la manipuler et de passer à la suivante pour mettre en place litération. Par ailleurs, chaque conteneur fourni un type ditérateur. Exemple le type list donne un itérateur de type : list :: iterator.

73 Tous les conteneurs offrent les mêmes fonctions de base permettant aux itérateurs daccéder aux éléments begin() Retourne un itérateur pointant au premier élément du conteneur end() Retourne un itérateur pointant après le dernier élément du conteneur size() Retourne le nombre déléments présents dans le conteneur Les itérateurs

74 L'itérateur est donc une généralisation des pointeurs. Il permet de parcourir en séquence les éléments d'un conteneur. Hiérarchie des itérateurs: EcritureLecture Forward Bidirectionnel Accès aléatoire It+n, It-n It++, It-- It++

75 Bidirectionnel peut itérer en direction avant (++) et arrière (--) type ditérateur des conteneurs list, set, multiset, map et multimap Accès par index peut itérer en direction avant (++), arrière (--) et par index ([ ]) type ditérateur des conteneurs vector et deque Les itérateurs Les catégories

76 Les itérateurs Première version: Une méthode hasNext() pour savoir si on est arrivé à la fin Une méthode next() pour passer à lélément suivant Ce type ditérateur est utilisé en Java Deuxième version: Litérateur est manipulé comme sil sagissait dun pointeur La manipulation se fait par la surcharge des opérateurs *, ++, --, ==, != et =. Ce type ditérateur est utilisé en C++ Implémentation

77 Les itérateurs Tous les conteneurs définissent deux types ditérateur container::iterator permet de naviguer en mode lecture/écriture container::const_iterator permet de naviguer en mode lecture seulement Utilisation

78 Les itérateurs Exemple 1#include Using namespace std; int main( ) { list list1; cin >> n; for (int i = 1; i<=n; i++) list1.push(i+i); list 1 :: iterator i; for (i = list1.begin( ); i!=list1.end( ); i++) cout <<*i << ; list :: reverse_iterator inv; for (inv = list1.rbegin( ); i!=list1.rend( ); rev++) cout <<*rev << ; return 0 ; }

79 Les itérateurs Dans lexemple précédent, on utilise également un itérateur inversé (reverse_iterator) qui permet le parcours dans le sens inverse. Les principaux opérateurs sont * donnant accès à la valeur, ++ et -- pour incrémenter et décrémenter une valeur. - Opérateur * : Retourne lélément de la position courante - Opérateur ++ : Fait pointer litérateur à lélément suivant - Opérateur == : Indique si 2 itérateurs pointent sur le même élément - Opérateur = : Assigne un itérateur

80 Les itérateurs Exemple 2 #include using namespace std;................. list nums; list ::iterator nums_iter; nums.push_back (0); nums.push_back (4); nums.push_front (7); cout << endl << "List 'nums' now becomes:" << endl; for (nums_iter=nums.begin(); nums_iter != nums.end(); nums_iter++) { *nums_iter = *nums_iter + 3; // Modifier chaque élément. cout << (*nums_iter) << endl; } cout << endl;

81 Les itérateurs Après la création dune liste dentiers, litérateur num_iter est initialisé pour spécifier la position de la liste (nums.begin()). La boucle est exécutée jusquà atteindre la valeur de litérateur représentant la position derrière le dernier élément de la liste (nums.end()). Chaque élément de la liste est accédé par lopérateur "*" qui retourne une référence à cet élément. Lopérateur dincrémentation (++) déplace litérateur à la position suivante dans la liste. Souvent, les éléments stockés dans une STL sont des classes. Dans pareils cas, il se pourrait que nous voulions invoquer les fonctions membre de cet objet référencé par litérateur. Pour ce faire, nous devons faire attention à la précédence des opérateurs pour que le compilateur puisse comprendre ce que nous sommes en train de faire.

82 Les itérateurs #include using namespace std;... list words; list ::iterator words_iter;... unsigned int total_length = 0; for (words_iter=words.begin(); words_iter != words.end(); words_iter++) { total_length += (*words_iter).length(); // correct // total_length += *words_iter.length(); // faux !! } cout << "Total length is " << total_length << endl; Exemple 3

83 Les itérateurs Les parenthèses entre "*words_iter" sont nécessaires quand nous invoquons la fonction "length( )". Sans elles, le compilateur va comprendre que la fonction "length( )" est membre de literateur, et non de la classe string class, car le "." de loperateur sera autrement évalué avant lopérateur "*". Remarquez que les parenthèses vont aussi être nécessaires lors de laccès aux données.

84 #include // création dune liste de caractères list coll; for (char c = a; c<=z; c++) coll.push_back(c); // impression de la liste à laide dun itérateur list ::const_iterator pos; for(pos = coll.begin(); pos != coll.end(); pos++) cout << *pos << ; Exemple 4 Les itérateurs

85 Synthèse Les itérateurs Plusieurs fonctions requièrent la notion de position dans un conteneur. Dans la STL une position est représentée par un type imbriqué que l'on nomme itérateur. Par exemple, on utilise le type vector ::iterator pour représenter une position dans un vector. Pour plus de concision nous écrirons simplement iterator.

86 Synthèse Les itérateurs iterator begin() Retourne un iterateur pointant au début du conteneur iterator end() Retourne un itérateur pointant à la fin du conteneur iterator insert (iterator p, const Object& x) Ajoute x immédiatement avant la position p. Cette opération prend un temps constant pour les listes mais pas pour les vecteurs. iterator erase (iterator p) Enlève l'objet à la position p. Retourne la position de l'objet suivant. iterator erase(iterator debut, iterator fin) Enlève tous les objets à partir de debut jusquà fin.

87 Synthèse Les itérateurs Si v est une variable de type vector alors on peut afficher ses éléments de la façon suivante: for (int i=0; i< v.size(); ++i) cout<<v[i]<<endl; On peut aussi utiliser la méthode suivante: for (vector ::iterator itr=v.begin(); itr!= v.end(); ++itr) cout<<*itr<<endl;

88 Itérateurs – Pour les arbres Chaque fois quon le fait avancer, litérateur pointe sur le noeud suivant dans un ordre pré-défini Pour un parcours pré-ordre, on peut faire une implémentation simple en utilisant une pile Les parcours en ordre et post-ordre sont un peu plus compliqués...

89 Arbres – Itérateur abstrait template class IterateurArbre { public: IterateurArbre(const Arbre & unArbre) : laRacine(unArbre.ptrRacine), actuel(NULL) {} virtual ~IterateurArbre(){} virtual void premier() = 0; bool estValide() const { return (actuel != NULL); } T extraire() const; // retourne la donnée à la position actuelle virtual void avancer() = 0; protected: const NoeudArbre *laRacine; const NoeudArbre *actuel; };

90 Arbres – Itérateur pré-ordre template class IterateurPreOrdre : public IterateurArbre { public: IterateurPreOrdre(const Arbre & unArbre); ~IterateurPreOrdre() {} virtual void premier(); virtual void avancer(); protected: Pile *> pileNoeuds; };

91 Arbres – Itérateur pré-ordre // Réinitialise l'itérateur en le faisant pointer // à la racine de l'arbre template void IterateurPreOrdre ::premier() { // Vider la pile pileNoeuds.vider(); if (laRacine != NULL) { pileNoeuds.push(laRacine); avancer(); }

92 Arbres – Itérateur pré-ordre template void IterateurPreOrdre ::avancer() { NoeudArbre *fils; if (pileNoeuds.empty()) { if (actuel == NULL) cout << "Tentative d'avancer au dela de la fin"; actuel = NULL; return; } actuel = pileNoeuds.top(); pileNoeuds.pop(); fils = actuel->obtenirFilsDroit(); if (fils != NULL) pileNoeuds.push(fils); fils = actuel->obtenirFilsGauche(); if (fils != NULL) pileNoeuds.push(fils); }

93 Les algorithmes La STL fournit un nombre important dalgorithmes génériques les plus utilisés, tels que les algorithmes de parcours, de recherche et de tri. Ils sappliquent sur les conteneurs. Les algorithmes ne sont pas des fonctions membres des classes des conteneurs. Ce sont plutôt des fonctions globales qui opèrent avec des intérateurs. Pour manipuler cette bibliothèque, il suffit dincorporer dans lentête #include On distingue deux types dalgorithmes: ceux qui modifient les conteneurs et ceux qui ne le modifient pas (remarquer que les algorithmes de tri font partie des algorithmes qui ne modifient pas les conteneurs).

94 Algorithmes de non modification (non mutating algorithms) find Trouver la première occurrence dune valeur donnée. find_ifTrouver la première apparition dun prédicat. find_first_of Trouver la première occurrence dune valeur dune séquence dans une autre. adjacent_find Trouver la première occurrence dune paire de valeurs adjacente count Compter lapparition dune valeur dans une séquence. count_if Compter le nombre de fois quun prédicat apparait dans une séquence. equal Comparaison élément à élément le contenu de deux conteneurs. Les conteneurs peuvent de types différents max_elementTrouver le plus grand élément dune séquence. min_elementTrouver le plus petit élément dune séquence. search Recherche la première occurrence dun sous ensemble déléments.

95 Algorithmes de non modification (non mutating algorithms) Exemple – for_each() void print(const int elem) { cout << elem << ' '; } int main() { vector coll;... for_each(coll.begin(), coll.end(), print); }

96 Algorithmes de non modification (non mutating algorithms) Exemple – count() et count_if() bool estPair(const int elem) { return (elem % 2 == 0); } int main() { vector coll;... count(coll.begin(), coll.end(), 3);... count_if(coll.begin(), coll.end(), estPair);

97 Algorithmes de non modification (non mutating algorithms) Exemple – find()... int tab[4] = {76,77,3,45}; vector ::const_iterator pos; for (i=0; i<3; i++){ pos = find(coll.begin(), coll.end(), tab[i]); if (pos != coll.end()) cout << "Element trouve: " << *pos << endl; else cout << "Element non trouve: " << tab[i] << endl; } les conteneurs associatifs ont une méthode find() qui fait la même chose, mais de manière plus efficace, en O(lg n)

98 Algorithmes de non modification (non mutating algorithms) Exemple – find_if() bool plusGrandQue10(const int elem) { return elem > 10; } int main() {... pos = find_if(coll.begin(), coll.end(), plusGrandQue10); if (pos != coll.end()) cout 10:" << *pos << endl; else cout 10: " << endl;

99 Algorithmes de non modification (non mutating algorithms) Exemple – search() vector coll2; coll2.push_back(3); coll2.push_back(1); coll2.push_back(3); pos = search(coll.begin(), coll.end(), coll2.begin(), coll2.end()); if (pos != coll.end()){ cout << "A partir de la sous-séquence trouvee: << endl; for_each(pos, coll.end(), print); cout << endl; } else cout << "Sous-sequence pas trouvee" << endl;

100 reverse()inverse l'ordre des éléments du conteneur partition() met au debut tous les éléments qui respectent la condition passée en paramètre sort() trie les éléments stable_sort() trie les éléments de manière à ce que les éléments égaux restent dans le même ordre Algorithmes qui altèrent lordre des données

101 Les algorithmes Exemple – partition() // Partitionne le conteneur en mettant les // nombre pairs au début partition(coll.begin(), coll.end(), estPair);

102 Les algorithmes #include // inclusion des algorithmes #include using namespace std; …………………………… vector vec; vec.push_back (10); vec.push_back (3); vec.push_back (7); sort(vec.begin(), vec.end()); // tri le vecteur // le vecteur contient maintenant : 3, 7, 10 Exemple – sort()

103 Algorithmes de modification (mutating algorithms) transform for_each Merge Modifie et copie les éléments dun conteneur Réalise sur tous les éléments lopération passée en paramètre Fusionne deux conteneurs triés en un seul ensemble trié de valeurs copy Copier une séquence replace Remplacer les éléments dune séquence par une valeur donnée. replace_if Remplacer les éléments égaux à une prédicat remove Supprimer toutes les occurences dun élément donné dans le conteneur remove_if Supprimer tous les éléments qui respectent à un prédicat passé en paramètre reverse Inverser une séquence. random_shuffle Aléatoirement réorganiser les éléments en utilisant une distribution uniforme. fill Remplacer les éléments dune séquence avec une valeur. generate Remplacer les éléments dune séquence avec le résultat dune opération donnée. accumulate Sommer les éléments dune séquence. unique Élimine tous les éléments qui sont égaux à leur prédécesseur

104 Les algorithmes Remarques sur remove() les listes ont leur propre méthode remove(), plus efficace Ne retire pas réellement les éléments du conteneur Les éléments sont retiré de la position où ils se trouvent et les reste est décalé en conséquence Par contre, comme la taille du conteneur ne change pas, on se retrouve à avoir à la fin des valeurs invalides La fonction remove() retourne un itérateur pointant sur la première position invalide Pour nettoyer le conteneur, on peut appeler erase à partir de cette position

105 Les algorithmes Exemple - remove() // retrait des occurrences de la valeur 2 vector ::iterator fin = remove(coll.begin(), coll.end(), 2); // ajustement du conteneur coll.erase(fin, coll.end());

106 Les algorithmes Exemple – remove_if() // Retrait des nombres pairs fin = remove_if(coll.begin(), coll.end(), estPair); coll.erase(fin,coll.end()); cout << "Apres retrait des nombres pairs: " << endl; for_each(coll.begin(), coll.end(), print); cout << endl

107 Les algorithmes #include List initC(char*c) { List majax; while (*c != \0= majax.push_back(*c++); return majax; } int main() { List gerard = initC("le plus grand et le plus fort des magiciens"); gerard.sort(); gerard.unique(); for (List ::iterator i = gerard.begin() ; i != gerard.end() ; i++) cout << *i; return 0; } Exemple 1 – unique()

108 Les algorithmes Exemple 2 – unique() // Elimination des répétitions fin = unique(coll.begin(), coll.end()); coll.erase(fin,coll.end()); cout << "Apres elimination des repetitions: " << endl; for_each(coll.begin(), coll.end(), print); cout << endl;

109 Pour encore plus de flexibilité, certains algorithmes permettent lusage de fonctions définies par lusager Les fonctions sont appelées à linterne par lalgorithme et généralement appliquées à chaque élément du conteneur Un prédicat est une fonction qui retourne une valeur booléenne (vrai ou faux) Les prédicats peuvent être utilisés pour spécifier un critère de recherche ou de tri Utilisation de prédicats dans les algorithmes

110 Différence entre for_each() et transform() for_each() requiert une fonction qui ne retourne aucune valeur, et qui modifiera directement chaque élément en le recevant par référence transform() requiert une fonction qui retourne la valeur modifiée, et qui sera copiée dans un second conteneur Remarque: le second conteneur peut être le même conteneur

111 Les algorithmes Exemple - for_each() void ajouter10(int & elem) { elem += 10; }... // Utilisation de for_each() qui altère les données for_each(coll.begin(), coll.end(), ajouter10); cout << endl;

112 Les algorithmes Exemple - transform() // Utilisation de transform() qui altère les données // et les envoie dans un autre conteneur vector coll2; coll2.resize(coll.size()); transform(coll.begin(), coll.end(), coll2.begin(), ajouter10bis); cout << endl;

113 Les algorithmes Exemple – fill_n() // Mettre des 0 dans la première moitié et //des 1 dans la seconde // On remplit la première moitié fill_n(coll.begin(),5,0); // On utilise un itérateur inverse pour // ajouter à partir de la fin fill_n(coll.rbegin(),5,1);

114 Les algorithmes Exemple – generate() int fibonacci() { static int n1 = 0; static int n2 = 1; int temp = n1 + n2; n1 = n2; n2 = temp; return n1; }

115 Les algorithmes Exemple – generate() // Utilisation de generate pour créer la // suite de Fibonacci generate(coll.begin(), coll.end(), fibonacci); cout << "Suite de Fibonacci: " << endl; for_each(coll.begin(), coll.end(), print); cout << endl;

116 Algorithmes de manipulation densembles includes Vérifie si les éléments dun conteneur forment un sous-ensemble dun autre conteneur set_unionRéalise lunion ensembliste de deux conteneurs set-intersection Réalise lintersection ensembliste de deux conteneurs binary_search Trouver une valeur donnée en utilisant la recherche dichotomique

117 Les algorithmes Exemple – includes() if (includes(c1.begin(), c1.end(), c2.begin(), c2.end())) cout << "c2 inclus dans c1" << endl; else cout << "c2 non inclus dans c1" << endl;

118 Les algorithmes Problèmes dutilisation #include list coll1; vector coll2; // insertion déléments dans la liste for (int i=1; i<=9; i++) coll1.push_back(i); // copie dans le vecteur (PROBLÈME À LEXÉCUTION) copy(coll1.begin(), coll1.end(), // source coll2.begin());// destination

119 Les algorithmes Problèmes dutilisation Lalgorithme copy écrase les éléments de la destination Or, au moment de lappel, le vecteur (coll2) est vide Dans un tel cas, il faudrait créer les éléments lors de la copie plutôt que décraser un élément qui nexiste pas! Solution: adaptateur ditérateur

120 Les algorithmes Adaptateur ditérateurs Il existe trois types ditérateurs adaptateurs insert: permet aux algorithmes dopérer en mode insertion plutôt quen mode écrasement Reprenons le cas de la copie… list coll1; // insertion déléments dans la liste for (int i=1; i<=9; i++) coll1.push_back(i);

121 Les algorithmes Adaptateur ditérateurs // copie dans un vector vector coll2; copy(coll1.begin(), coll1.end(), // source back_inserter(coll2));// destination // copie dans un deque deque coll3; copy(coll1.begin(), coll1.end(), // source front_inserter(coll3));// destination // copie dans un set set coll4; copy(coll1.begin(), coll1.end(), // source inserter(coll4, coll4.begin());// destination

122 Les algorithmes Adaptateur ditérateurs, autre exemple int main() { int t1[] = { 1, 3, 5, 7, 9}; deque dq1(t1,t1+5); int t2[] = { 2, 4, 6}; deque dq2(t2,t2+3); copy(dq1.begin(), dq1.end(), back_inserter(dq2)); for (int i=0 ; i<dq2.size() ; i++) cout << dq2[i] << ; return 0; }

123 Les algorithmes Adaptateur ditérateurs - Ensemble // intersection de deux ensembles vector c1,c3,c4;... set_intersection(c1.begin(), c1.end(), c3.begin(), c3.end(), back_inserter(c4));

124 Les algorithmes Adaptateur ditérateurs Les deux autre types dadaptateurs sont stream: permet de lire ou décrire des « stream » (accès direct au clavier et à lécran reverse: opère en mode inverse (pour afficher un tableau à lenvers, par exemple)

125 Les algorithmes La STL fournit aussi des utilitaires qui augmentent les capacités des algorithmes : Foncteurs (objets de fonction) Adaptateurs de fonctions

126 Les foncteurs Un foncteur est un objet se comportant comme une fonction Repose sur la surcharge de lopérateur () class PrintInt { public: void operator() (int elem) { cout << elem << ; } }; int main() { vector coll;... for_each (coll.begin(), coll.end(), PrintInt()); cout << endl; return 0; } Exemple

127 Les foncteurs Attention: lexpression PrintInt() crée un objet temporaire On crée dabord lobjet, quon utilise ensuite comme foncteur Exemple 1 PrintInt unFoncteur; unFoncteur(8); // imprime lentier 8

128 Les foncteurs Permet de définir des fonctions « intelligentes », en utilisant dautres fonctions et données membres Chaque instance de la fonction peut avoir un état différent Avec une fonction ordinaire, on ne pourrait pas par exemple avoir une variable statique avec plusieur valeurs initiales différentes, ce qui est possible avec un foncteur Avantages

129 Les foncteurs Exemple 2 Supposons que lon veuille une fonction qui incrémente dune certaine valeur un élément Si la valeur est fixe et connue davance, on peut utiliser une fonction normale: void ajouter10(int & elem) { elem += 10; } int main() { vector unTableau;... transform(unTableau.begin(), unTableau.end(), unTableau.begin(), ajouter10);... }

130 Les foncteurs Exemple 2 suite Si la valeur est variable, mais connue lors de la compilation, on utilise un template: template void ajouter(int & elem) { elem += laValeur; } int main() { vector unTableau;... transform(unTableau.begin(), unTableau.end(), unTableau.begin(), ajouter );... }

131 Les foncteurs Si la valeur est variable, mais connue seulement lors de lexécution, on utilise un foncteur: class Ajouter { public: Ajouter(int v) : laValeur(v) {} void operator() (int & elem) const { elem += laValeur; } private: int laValeur; } Utilisation int increment; cin >> increment; for_each(unTableau.begin(), unTableau.end(), Ajouter(increment));

132 Les foncteurs Exemple 3 class FiltrerLettres { public: FiltrerLettres(const char* lesLettres = "") {strcpy(lettresFiltrees,lesLettres);} bool operator () (char c) const { int i = 0; while (lettresFiltrees[i] != 0) { if (c == lettresFiltrees[i]) return true; ++i; } return false; } private: char lettresFiltrees[27]; };

133 Les foncteurs Exemple 3 suite int main() { list uneListe; for (char c='a'; c<='z'; ++c){ uneListe.push_back(c); } remove_if(uneListe.begin(),uneListe.end(), FiltrerLettres("aeiou")); while (!uneListe.empty()){ cout << uneListe.front() << ' '; uneListe.pop_front(); } cout << endl; return 0; }

134 Les foncteurs prédéfinis STL offrent plusieurs foncteurs couvrant les opérations de base Par exemple, le conteneur set trie ses éléments en ordre croissant. Pour utiliser un autre critère de tri, on na quà utiliser un autre prédicat set coll; // trie en ordre croissant (par défaut) set > coll; // trie en ordre décroissant greater est un foncteur prédéfini

135 Les foncteurs prédéfinis Exemple de traitement numérique transform(coll.begin(), coll.end(), coll.begin(), negate ()); negate est un foncteur qui multiplie la valeur par -1

136 Adaptateurs de fonctions Il sagit de foncteurs qui permettent de combiner des fonctions. Exemple plus le foncteur pré-défini qui effectue une addition sur des entiers bind2nd(op,valeur) est un foncteur pré-defini qui prend une fonction à deux arguments et la transforme en un nouvelle fonction où le second argument est la valeur spécifiée bind2nd(plus (),10) est donc une fonction qui prend un seul argument et qui ajoute 10 à cet argument

137 Adaptateurs de fonctions Exemple 1 int main() { vector vect; vect.push_back(2); vect.push_back(7); vect.push_back(10); for_each(vect.begin(), vect.end(), PrintInt()); cout << endl; transform(vect.begin(), vect.end(), vect.begin(), bind2nd(plus (),10) ); cout << endl; for_each(vect.begin(), vect.end(), PrintInt()); cout << endl; return 0; }

138 Adaptateurs de fonctions Exemple 2 int main() { vector coll; int resultat; for (int i = 1; i < 5; i++) coll.push_back(i); // Calculer le produit resultat = accumulate(coll.begin(), coll.end(), 1, multiplies ()); return 0; }

139 STL : Standard Template Library Pour plus dinformations sur les STL, consulter par exemple le lien suivant : http://www.sgi.com/tech/stl/stl_introduction.html


Télécharger ppt "Structures de données IFT-2000 Abder Alikacem Standard Template library Édition Septembre 2009 Département dinformatique et de génie logiciel."

Présentations similaires


Annonces Google