Génie Logiciel I - Cours VII - La S.T.L. et les conteneurs
Transcription
Génie Logiciel I - Cours VII - La S.T.L. et les conteneurs
Génie Logiciel I Cours VII - La S.T.L. et les conteneurs Nicolas Kielbasiewicz C.D.C.S.P./I.S.T.I.L./I.C.J. Filière M.A.M. 2ème année - 08/09 Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 1 / 37 Génie Logiciel I Filière M.A.M. 2ème année - 08/09 2 / 37 Plan du cours 1 Généralités sur la S.T.L. 2 Les conteneurs séquentiels 3 Les conteneurs associatifs Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Généralités sur la S.T.L. La S.T.L. Definition (S.T.L.) La S.T.L. ou Standard Template Library est la grande nouveauté de la bibliothèque standard intégrée à la norme C++. Elle contient un ensemble de patrons de classes permettant de manipuler simplement les éléments du C++. Ex : les classes de flots, la classe string, la classe type info, la classe exception et ses dérivées, . . . La S.T.L. introduit de nouvelles notions : les conteneurs; les itérateurs; les algorithmes; les prédicats. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 3 / 37 Généralités sur la S.T.L. Les conteneurs Definition (Les conteneurs) Les conteneurs sont des classes permettant de représenter les structures de données les plus répandues : listes, vecteurs, ensembles, tableaux associatifs, . . . Ce sont des patrons de classes paramétrés par le type de leurs éléments. Chacune de ces classes dispose de fonctionnalités appropriées et en tant que patrons, peuvent être instanciées pour n’importe quel paramètre, y compris un paramètre de type classe défini par l’utilisateur. Beaucoup de fonctionnalités sont communes à différents conteneurs. Il existe deux types de conteneurs : les conteneurs séquentiels : ce sont des conteneurs dont les éléments sont ordonnés. On peut parcourir le conteneur suivant cet ordre et insérer ou supprimer un élément en un endroit explicitement choisi; les conteneurs associatifs : ce sont des conteneurs dont les éléments sont identifiés par un clé et ordonnés suivant celle-ci. Pour insérer un élément, il n’est en théorie plus utile de préciser un emplacement. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 4 / 37 Généralités sur la S.T.L. Les itérateurs : rappels sur les pointeurs Parcours ”classique” d’un tableau double p t r [ 6 ] ; f o r ( i n t j =0; j <6; j ++) { c o u t << p t r [ j ] << e n d l ; } Parcours d’un tableau avec pointeur double p t r [ 6 ] ; double ∗ i=new double ( ) ; i f o r ( i=&p t r ; i !=& p t r +6; i ++) { c o u t << ∗ i << e n d l ; } Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I ptr[0] ptr[1] ptr[2] ptr[3] ptr[4] ptr[5] Filière M.A.M. 2ème année - 08/09 5 / 37 Généralités sur la S.T.L. Les itérateurs Definition (itérateur) Un itérateur est un objet défini par la classe conteneur concernée. Il généralise la notion de pointeur : à un instant donné, un itérateur possède une valeur qui désigne un élément donné du conteneur. On dit qu’ un itérateur pointe vers un élément du conteneur; un itérateur peut être incrémenté par l’opérateur ++, de manière à pointer vers l’élément suivant du conteneur; un itérateur peut être déréférencé, comme un pointeur, à l’aide de l’opérateur *. Par exemple, si it est un itérateur sur une liste de points, *it désigne un point de la liste; deux itérateurs sur un même conteneur peuvent être comparés par égalité ou inégalité. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 6 / 37 Généralités sur la S.T.L. Les itérateurs Il existe 3 principaux types d’itérateurs : les itérateurs unidirectionnels : ce sont des itérateurs qui ne peuvent qu’être incrémentés (++); les itérateurs bidirectionnels : ce sont des itérateurs qui peuvent être incrémentés (++) et décrémentés (–); les itérateurs à accès direct : ce sont des itérateurs bidirectionnels pour lesquels les expressions de la forme it+i ont un sens. Dans ce cas, on surdéfinit souvent l’opérateur []. Les itérateurs à accès direct peuvent être comparés par inégalité. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 7 / 37 Généralités sur la S.T.L. Utilisation des itérateurs Pour parcourir un conteneur avec un itérateur, on dispose de deux fonctions begin() et end() retournant une valeur de type itérator pour un parcours direct, et de deux fonctions rbegin() et rend() retournant une valeur de type reverse iterator pour un parcours inverse (pour les itérateurs au moins bidirectionnels) : Exemple l i s t <p o i n t > l p ; ... // i t é r a t e u r s u r l i s t e de p o i n t s l i s t <p o i n t > : : i t e r a t o r i t ; f o r ( i t =l p . b e g i n ( ) ; i t != l p . end ( ) ; i t ++) { ... } ... // i t é r a t e u r i n v e r s e s u r l i s t e de p o i n t s l i s t <p o i n t > : : r e v e r s e i t e r a t o r r i t ; f o r ( r i t =l p . r b e g i n ( ) ; r i t != l p . r e n d ( ) ; r i t ++) { ... } Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 8 / 37 Généralités sur la S.T.L. Les intervalles d’itérateurs Comme nous l’avons précisé, tous les conteneurs sont ordonnés, de sorte que l’on peut toujours les parcourir d’un début jusqu’à une fin. Definition (intervalle d’itérateur) On appelle intervalle d’itérateur d’un conteneur un couple de valeurs de deux itérateurs it1 et it2 précisant les bornes. On le note [it1,it2). Cela signifie qu’à partir de l’élément du conteneur pointé par it1, on peut atteindre l’élément pointé par it2 à l’aide d’un certain nombre d’incrémentations. L’intervalle d’itérateur [it1,it2) contiendra la séquence des éléments pointés durant le parcours, de l’élément pointé par it1 inclus à l’élément pointé par it2 exclu. Cette notion d’intervalle d’itérateur sera très utilisée dans les algorithmes. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 9 / 37 Généralités sur la S.T.L. Les algorithmes La notion d’algorithme est tout aussi originale que les deux précédentes. Elle se fonde sur le principe suivant : Par le biais des itérateurs, beaucoup d’opérations peuvent être appliquées à un conteneur quels que soient sa nature et le type de ses éléments. Par exemple, on peut trouver le premier élément ayant une valeur donnée aussi bien dans une liste que dans un vecteur ou un ensemble. Le seul besoin est que l’égalité entre deux éléments soit convenablement définie. De même, on peut trier un conteneur de type quelconque, y compris un type classe défini par l’utilisateur, à la condition que le conteneur en question dispose d’un itérateur à accès direct et que la relation d’ordre < soit convenablement définie. Definition (algorithme) Un algorithme est un patron de fonction dont le paramètre est le type des itérateurs fournis en arguments. L’utilisation des algorithmes standards demandera d’include <algorithm>. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 10 / 37 Généralités sur la S.T.L. Exemples d’algorithmes Compter le nombre d’occurences d’une valeur dans un intervalle d’itérateur : l’algorithme count v e c t o r <i n t > v ; i n t n=c o u n t ( v . b e g i n ( ) , v . end ( ) , 1 ) ; l i s t <double> l ; i n t m=c o u n t ( l . b e g i n ( ) , l . end ( ) , 2 . 0 ) ; Copier une séquence de valeurs dans un autre (type de) conteneur : l’algorithme copy v e c t o r <double> v , w ; l i s t <double> l ; copy ( v . b e g i n ( ) , v . end ( ) , l . b e g i n ( ) ) ; copy ( v . r b e g i n ( ) , v . r e n d ( ) , w . b e g i n ( ) ) ; Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 11 / 37 Généralités sur la S.T.L. Fonctions unaires Beaucoup d’algorithmes et quelques fonctions membres des classes conteneurs permettent d’appliquer une fonction aux éléments d’une séquence. Cette fonction est simplement passée en argument de l’algorithme : Exemple : for each main ( ) { l i s t <f l o a t > l f ; void a f f i c h e ( f l o a t ) ; ... f o r e a c h ( l f . b e g i n ( ) , l f . end ( ) , a f f i c h e ) ; c o u t << e n d l ; ... } v o i d a f f i c h e ( f l o a t x ) { c o u t << x << ” ”; } Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 12 / 37 Généralités sur la S.T.L. Fonctions, prédicats et classes fonctions Definition (Prédicat) Un prédicat est une fonction dont la valeur de retour est de type bool. Là encore, certains algorithmes et fonctions membres des classes conteneurs demandent un prédicat en argument. Exemple : find if main ( ) { l i s t <i n t > l ; l i s t <i n t > : : i t e r a t o r i t ; bool i m p a i r ( i n t ) ; i t = f i n d i f ( l . b e g i n ( ) , l . end ( ) , i m p a i r ) ; } b o o l i m p a i r ( i n t i ) { r e t u r n i %2;} Dans la plupart des cas, les fonctions passées en arguments sont des objets fonctions. Pour utiliser les classes fonctions prédéfinies, on inclura <functional>. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 13 / 37 Généralités sur la S.T.L. Conteneurs, algorithmes et relation d’ordre par définition, les conteneurs séquentiels sont ordonnés. Par ailleurs, le conteneur list dispose d’une fonction membre sort qui permet de les réarranger selon un certain critère; pour des raisons d’efficacité, les éléments d’un conteneur associatif sont ordonnés; il existe beaucoup d’algorithmes de tri qui réorganisent également les éléments d’un conteneur suivant un certain ordre. Tant que les éléments concernés sont d’un type standard (type de base ou string) on peut se permettre d’appliquer ces méthodes de réordonnancement sans se poser de questions. Par contre, si les élements concernés sont de type classe, il faut s’assurer de la surcharge de l’opérateur <, et pas n’importe comment. On peut également choisir d’utiliser une relation autre que l’opérateur <, soit en choisissant un autre opérateur, soit en fournissant une fonction de comparaison de deux éléments. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 14 / 37 Généralités sur la S.T.L. Conteneurs, algorithmes et relation d’ordre Quel que soit le choix de la relation d’ordre R, R doit être une relation d’ordre faible strict, c’est-à-dire vérifie les propriétés suivantes : 1 la comparaison de deux éléments identiques retourne la valeur faux : ∀a !(aRa); 2 la relation d’ordre est transitive : si aRb et bRc, alors aRc; 3 si !(aRb) et !(bRc), alors !(aRc). Pour des valeurs numériques, on peut donc utiliser les opérateurs < et >, mais pas les opérateurs <= et >=, qui ne sont pas des relations d’ordre faible strict. Il faudra faire bien attention à respecter ces propriétés lors de la définition de la relation d’ordre sur un conteneur associatif, comme nous le verrons. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 15 / 37 Les conteneurs séquentiels Généralités Definition Les conteneurs séquentiels sont des conteneurs ordonnés suivant un ordre imposé explicitement par le programme lui-même. Il existe 3 conteneurs séquentiels principaux : list : ce conteneur correspond à la liste doublement chaı̂née; vector : ce conteneur correspond à la généralisation des tableaux; deque : ce conteneur est intermédiaire entre list et vector et n’existe que pour des raisons d’efficacité. En tant que conteneurs, les trois ont des fonctionnalités communes. Ils ont aussi des fonctionnalités propres. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 16 / 37 Les conteneurs séquentiels Fonctionnalités communes à list, vector et deque Les fonctionnalités communes sont de 4 types : 1 la construction; 2 l’affectation globale; 3 la comparaison; 4 l’insertion / suppression d’éléments. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 17 / 37 Les conteneurs séquentiels Construction Les conteneurs list, vector et deque disposent de différents constructeurs : construction d’un conteneur vide : l i s t <i n t > l i ; v e c t o r <f l o a t > v f ; construction avec un nb donné d’éléments, initialisés par une valeur ou pas : l i s t <i n t > l i ( 1 0 ) ; point p (2 ,3); deque<p o i n t > dd ( 5 , p ) ; construction à partir d’une séquence : l i s t <i n t > l i ( 5 ) ; v e c t o r <i n t > v f ( l i . b e g i n ( ) , l i s t <i n t > l i r ( l i . r b e g i n ( ) , l i . end ( ) ) ; l i . rend ( ) ) ; construction par copie : l i s t <i n t > l i ; l i s t <i n t > l i 2 ( l i ) ; Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 18 / 37 Les conteneurs séquentiels Modifications globales affectation : elle n’est possible qu’entre conteneurs de même type; l i s t <i n t > l i ( . . . ) , l i 2 l i s t <f l o a t > l f ( . . . ) ; l i 2 = l i ; // c o r r e c t l i 2 = l f ; // i n c o r r e c t (...); fonction membre assign : permet d’affecter à un conteneur existant les éléments d’une séquence définie par un intervalle [deb,fin) ; l i s t <i n t > l i ( . . . ) ; v e c t o r <i n t > v i ( . . . ) ; l i s t <f l o a t > l f ( . . . ) ; v i . a s s i g n ( l i . b e g i n ( ) , l i . end ( ) ) ; // c o r r e c t v i . a s s i g n ( 1 0 , 1 ) ; // c o r r e c t : 10 é l é m e n t s v a l a n t 1 v i . a s s i g n ( l f . r b e g i n ( ) , l f . r e n d ( ) ) ; // i n c o r r e c t Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 19 / 37 Les conteneurs séquentiels Modifications globales fonction membre clear : vide le conteneur de son contenu; l i s t <i n t > l i ( . . . ) ; l i . clear (); fonction membre swap : permet d’échanger le contenu de deux conteneurs de même type ; l i s t <i n t > l i ( . . . ) , l i . swap ( l i 2 ) ; Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) li2 (...); Génie Logiciel I Filière M.A.M. 2ème année - 08/09 20 / 37 Les conteneurs séquentiels Comparaison l’opérateur == : retourne vrai si les deux conteneurs passés en arguments sont de même type, de même taille et ont le même contenu. A surdéfinir si besoin; < : retourne faux si l’une des comparaisons lexicographiques entre éléments de même rangs est fausse. Les deux conteneurs comparés ne sont pas nécessairement de même taille ; Exemple i n t t1 [ ] = {2 , 5 , 2 , 4 , 8}; i n t t2 [ ] = {2 , 5 , 2 , 8}; v e c t o r <i n t > v1 ( t1 , t 1 +5); v e c t o r <i n t > v2 ( t2 , t 2 +4); v e c t o r <i n t > v3 ( t2 , t 2 +3); v e c t o r <i n t > v4 ( v3 ) ; v e c t o r <i n t > v5 ; Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) v2 v5 v5 v3 v3 v2 Génie Logiciel I < v1 ; < v4 ; < v5 ; < v2 ; == v4 ; == v3 ; Filière M.A.M. 2ème année - 08/09 21 / 37 Les conteneurs séquentiels Comparaison l’opérateur == : retourne vrai si les deux conteneurs passés en arguments sont de même type, de même taille et ont le même contenu. A surdéfinir si besoin; < : retourne faux si l’une des comparaisons lexicographiques entre éléments de même rangs est fausse. Les deux conteneurs comparés ne sont pas nécessairement de même taille ; Exemple i n t t1 [ ] = {2 , 5 , 2 , 4 , 8}; i n t t2 [ ] = {2 , 5 , 2 , 8}; v e c t o r <i n t > v1 ( t1 , t 1 +5); v e c t o r <i n t > v2 ( t2 , t 2 +4); v e c t o r <i n t > v3 ( t2 , t 2 +3); v e c t o r <i n t > v4 ( v3 ) ; v e c t o r <i n t > v5 ; Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I v2 v5 v5 v3 v3 v2 < v1 ; // f a l s e < v4 ; // t r u e < v5 ; // f a l s e < v2 ; // t r u e == v4 ; // t r u e == v3 ; // f a l s e Filière M.A.M. 2ème année - 08/09 22 / 37 Les conteneurs séquentiels Insertion / suppression fonction membre insert : l i s t <double> l d ; l i s t <double > : : i t e r a t o r i t ; ... ld . insert ( il , 2 . 5 ) ; ld . i n s e r t ( ld . begin ( ) , 6 . 7 ) ; l d . i n s e r t ( l d . end ( ) , 3 . 2 ) ; ld . i n s e r t ( i l ,10 , −1.0); v e c t o r <double> vd ( . . . ) ; l d . i n s e r t ( l d . end ( ) , vd . b e g i n ( ) , vd . end ( ) ) ; fonction membre erase : supprime des éléments et retourne la valeur de l’élément suivant le dernier supprimé : l i s t <double> l d ; l i s t <double > : : i t e r a t o r i t 1 , i t 2 ; ... i t 1=l d . e r a s e ( i t 1 , i t 2 ) ; i t 2=l d . e r a s e ( l d . b e g i n ( ) ) ; Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 23 / 37 Les conteneurs séquentiels Le conteneur list Alors que les conteneurs vector et deque disposent d’un itérateur à accès direct (ce qui permet de les manipuler comme de simples tableaux), le conteneur list ne dispose que d’un itérateur bidirectionnel. On peut donc parcourir un conteneur list dans les deux sens, sans pour autant avoir la possibilité d’accéder à un élément par un indice. Le conteneur list est également le conteneur le plus efficace et rapide pour les opérations d’insertion / suppression (coût en O(1) plutôt qu’en O(n) pour vector et deque. Nous allons voir maintenant quelles sont les fonctionnalités spécifiques au conteneur list, les fonctionnalités communes vues précédemment étant bien évidemment disponibles. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 24 / 37 Les conteneurs séquentiels Le conteneur list Le conteneur list ne dispose que d’un itérateur bidirectionnel. On ne peut donc pas accéder directement à un élément de la liste. Il dispose néanmoins de deux fonctions membres sans arguments back et front permettant d’accéder au dernier / premier élément. Exemple l i s t <i n t > l i ( . . . ) ; i f ( l i . f r o n t ( ) == 9 9 ) l i . f r o n t ()=0; Le conteneur list dispose également de deux fonctions membres remove et remove if permettant de supprimer des éléments par valeur ou suivant un prédicat : Exemple b o o l p a i r e ( i n t n ) { r e t u r n n %2;} i n t t [ ] = {1 , 3 , 1 , 6 , 4 , 1 , 5 , 2 , 1}; l i s t <i n t > l i ( t , t +9); l i . remove ( 1 ) ; // l i c o n t i e n t 3 , 6 , 4 , 5 e t 2 l i . r e m o v e i f ( p a i r e ) ; // l i c o n t i e n t 3 e t 5 Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 25 / 37 Les conteneurs séquentiels Le conteneur list Nous allons voir maintenant quelques opérations globales : tri : le conteneur list dispose d’une fonction membre sort très efficace, permettant de trier ses élements : #i n c l u d e <f u n c t i o n a l > ... i n t t [ ] = {1 , 6 , 3 , 9 , 11 , 18 , 5}; l i s t <i n t > l i ( t , t +7); l i . s o r t ( ) ; // 1 , 3 , 5 , 6 , 9 , 1 1 , 1 8 , l i . s o r t ( g r e a t e r <i n t >); // 1 8 , 1 1 , 9 , 6 , 5 , 3 , 1 suppression des doublons : le conteneur list dispose d’une fonction membre unique très efficace, permettant d’éliminer les doublons quand ils sont consécutifs : i n t t [ ] = {1 , 6 , 6 , 4 , 6 , 5 , 5 , 4 , 2}; l i s t <i n t > l i ( t , t +9); l i s t <i n t > l i 2 = l i ; l i 1 . u n i q u e ( ) // 1 , 6 , 4 , 6 , 5 , 4 , 2 l i 2 . s o r t ( ) ; // 1 , 2 , 4 , 4 , 5 , 5 , 6 , 6 , 6 l i 2 . u n i q u e ( ) ; // 1 , 2 , 4 , 5 , 6 Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 26 / 37 Les conteneurs séquentiels Le conteneur list Voici un exemple permettant d’illustrer les diverses fonctionnalités abordées (il y en a d’autres, bien entendu) sur le conteneur list : Le programme test #i n c l u d e <i o s t r e a m > #i n c l u d e < l i s t > u s i n g namespace s t d ; main ( ) { v o i d a f f i c h e ( l i s t <char >); char mot [ ] = { ” a n t i c o n s t i t u t i o n n e l l e m e n t ”} ; l i s t <char> l c 1 ( mot , mot+s i z e o f ( mot ) −1); l i s t <char> l c 2 ; c o u t << ” l c 1 i n i t : ” << a f f i c h e ( l c 1 ) << e n d l ; c o u t << ” l c 2 i n i t : ” << a f f i c h e ( l c 2 ) << e n d l ; ... Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 27 / 37 Les conteneurs séquentiels Le conteneur list Le programme test (suite) ... l i s t <char > : : i t e r a t o r i t 1 , i t 2 ; i t 2=l c 2 . b e g i n ( ) ; f o r ( i t 1=l c 1 . b e g i n ( ) ; i t 1 != l c 1 . end ( ) ; i t 1 ++) i f ( ∗ i l 1 != ’ t ’ ) l c 2 . p u s h b a c k ( ∗ i l 1 ) ; // e n l e v e r l e s c o u t << ” l c 2 a p r e s : ” ; a f f i c h e ( l c 2 ) ; l c 1 . remove ( ’ t ’ ) ; c o u t << ” l c 1 remove : ” ; a f f i c h e ( l c 1 ) ; i f ( l c 1 == l c 2 ) c o u t << ” l e s deux l i s t e s s o n t e g a l e s ” << e n d l ; ’t ’ lc1 . sort (); c o u t << ” l c 1 s o r t : ” ; a f f i c h e ( l c 1 ) ; lc1 . unique ( ) ; c o u t << ” l c 1 u n i q u e : ” ; a f f i c h e ( l c 1 ) ; } Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 28 / 37 Les conteneurs séquentiels Le conteneur list Fonction affiche et sortie écran v o i d a f f i c h e ( l i s t <char> l c ) l i s t <char > : : i t e r a t o r i t ; f o r ( i t =l c . b e g i n ( ) ; i t != l c . end ( ) ; i t ++) c o u t << ( ∗ i t ) << ” ” ; c o u t << e n d l ; } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− lc1 i n i t : a n t i c o n s t i t u t i o n n e l l e m e n t lc2 i n i t : lc2 apres : a n i c o n s i u i o n n e l l e m e n l c 1 remove : a n i c o n s i u i o n n e l l e m e n l e s deux l i s t e s s o n t e g a l e s lc1 sort : a c e e e i i i l l m n n n n n o o s u lc1 unique : a c e i l m n o s u −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 29 / 37 Les conteneurs associatifs Généralités Definition Les conteneurs associatifs sont destinés à retrouver une information, non pas en fonction de sa place dans le conteneur, mais en fonction de sa valeur, ou une partie de sa valeur appelée clé. Pour des raisons d’efficacité, un conteneur associatif se trouve ordonné en permanence, en se fondant sur une relation d’ordre définie à la construction. Ex : dans un répertoire téléphonique, les numéros de téléphones sont ordonnés par une clé que constitue le nom et le prénom de la personne. À la différence des conteneurs séquentiels, chaque élément est ici composé de deux parties : la clé et la valeur. Les deux conteneurs associatifs les plus importants sont : map : conteneur associatif pur qui impose l’unicité des clés. On peut donc utiliser à bon escient l’opérateur []; multimap : à la différence de map, l’unicité de la clé n’est pas exigée. Dans l’exemple du répertoire téléphonique, le conteneur multimap autorisera les homonymes. Les deux classes n’ont pas vraiment de fonctionnalités communes en raison de l’unicité de la clé ou pas. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 30 / 37 Les conteneurs associatifs Le conteneur map Exemple #i n c l u d e <i o s t r e a m > #i n c l u d e <map> u s i n g namespace s t d ; main ( ) { v o i d a f f i c h e ( map<char , i n t >); map<char , i n t > m; c o u t << ”map i n i t : ” ; a f f i c h e (m) ; m[ ’ S ’ ] = 5 ; m[ ’C ’ ] = 1 2 ; c o u t << ”map SC : ” ; a f f i c h e (m) ; c o u t << ”map ( S ) : ” << m[ ’ S ’ ] << e n d l ; c o u t << ”map (X) : ” << m[ ’X ’ ] << e n d l ; c o u t << ”map X : ” ; a f f i c h e (m) ; m[ ’ S ’ ]=m[ ’ c ’ ] ; c o u t << ”map f i n a l : ” ; a f f i c h e (m) ; } Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 31 / 37 Les conteneurs associatifs Le conteneur map Exemple(suite) v o i d a f f i c h e ( map<char , i n t > m) { map<char , i n t > : : i t e r a t o r i t ; f o r ( im=m. b e g i n ( ) ; i t !=m. end ( ) ; i t ++) c o u t << ”( ” << im−> f i r s t << ” , ” << im−>s e c o n d << ”) ” ; c o u t << e n d l ; } −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− map i n i t : map SC = (C , 1 2 ) ( S , 5 ) map ( S ) : 5 map (X) : 0 map X : (C , 1 2 ) ( S , 5 ) (X , 0 ) map f i n a l : (C , 1 2 ) ( S , 0 ) (X , 0 ) ( c , 0 ) −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 32 / 37 Les conteneurs associatifs Le conteneur map Analysons cet exemple introductif : la classe map dispose d’un itérateur iterator bidirectionnel; les éléments d’un objet de type map sont d’un type particulier pair, dont la classe comporte deux attributs, first et second, pour accéder respectivement à la clé et à la valeur; lorsqu’on utilise l’opérateur [], si la clé utilisée n’existe pas dans le conteneur, elle est créée et la valeur associée sera 0; le conteneur map est ordonné intrinsèquement. Ici c’est l’opérateur < par défaut. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 33 / 37 Les conteneurs associatifs Le conteneur map Pour construire un conteneur map, on ne dispose que de 3 possibilités : construire un conteneur vide; construire un conteneur par copie; construire un conteneur à partir d’une séquence; La syntaxe est la même que celle vue pour les conteneurs séquentiels. On peut spécifier la relation d’ordre utilisée à l’aide d’un prédicat. Rappelons que par défaut, c’est l’opérateur < pour le type de la clé qui est utilisé. Si c’est un type classe, on s’assurera de le surcharger. map<char , long , g r e a t e r <char> > m1 ; map<char , long , g r e a t e r <char> > m2(m1 ) ; Dans le cas de la construction par copie, si m1 et m2 ne sont pas ordonnés par la même relation, il y a erreur de compilation : La relation d’ordre fait partie du type du conteneur. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 34 / 37 Les conteneurs associatifs Le conteneur map Comme pour tout conteneur, on peut accéder à un élément existant, soit pour en connaı̂tre la valeur, soit pour la modifier. Néanmoins, dans le cas d’une map, c’est un peu particulier. On a vu en effet qu’une tentative d’accès à une clé existante amène à la création d’un nouvel élément. Si l’on accède aux éléments par itérateur, ce comportement automatique n’existe plus. En théorie, il n’est pas interdit de modifier la valeur de l’élément désigné par un itérateur, mais le rôle exact d’une telle opération n’est pas spécifié par la norme. ... // m o d i f p a r a p p e l à f c t membre m a k e p a i r de c l a s s e p a i r ∗ i t =m a k e p a i r ( ’R ’ , 4 ) ; En effet, on peut modifier la valeur de la clé et l’ordre des éléments peut s’en trouver modifié. Sur quoi pointe alors l’itérateur ? Il est donc fortement déconseillé de modifier la valeur d’un élément d’une map par le biais d’un itérateur. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 35 / 37 Les conteneurs associatifs Le conteneur map Quelques fonctions membres utiles : find : permet de recherche un élément et retourne un itérateur. Si l’élément est introuvable, elle retourne end() : i f (m1 . f i n d ( ’R ’ )!=m1 . end ( ) ) c o u t << ”t r o u v é ”<<e n d l ; insert : permet d’insérer un élément. Les syntaxes sont les mêmes que vues précédemment; erase : permet de supprimer un élément. Les syntaxes sont les mêmes que vues précédemment. Il existe une nouvelle possibilité : donner la clé en argument. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 36 / 37 Les conteneurs associatifs Le conteneur map Que se passe t-il quand on veut supprimer un élément en passant un itérateur en argument ? Sur quoi va pointer l’itérateur ? La réponse dépend de la version du compilateur. Toutefois, il existe une manière de contourner le problème : Exemple t e m p l a t e < c l a s s T> e r a s e Z e r o s ( map<i n t , T> m) { typename map<i n t , T> : : i t e r a t o r i t ; f o r ( i t =m. b e g i n ( ) ; i t !=m. end ( ) ; ) { i f ( ( i t −>s e c o n d )==0.0){ m. e r a s e ( i t ++); } else { ++i t ; } } } On peut voir le mot clé typename dans la syntaxe de déclaration de l’itérateur, nécessaire dans ce cas. Il permet de signifier au compilateur que le type de l’itérateur sera décidé à l’utilisation. Nicolas Kielbasiewicz (C.D.C.S.P./I.S.T.I.L./I.C.J.) Génie Logiciel I Filière M.A.M. 2ème année - 08/09 37 / 37
Documents pareils
Le Traitement des données avec la STL (pdf - David Saint
Un « Foncteur » est un objet dont la classe définit l'opérateur « () ». Les foncteurs qui prennent :
• un paramètre sont dites foncteurs «unaires»,
• deux paramètres sont dits foncteurs «binaires»....
Les transparents du cours 3
for (vector