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

Présentations similaires


Présentation au sujet: "Structures de données IFT-2000"— Transcription de la présentation:

1 Structures de données IFT-2000
Abder Alikacem Types de données abstraits (2) Semaine 1 Édition Septembre 2009 Département d’informatique et de génie logiciel

2 Plan Exemple d’un TDA: une liste ordonnée
Utilités Spécifications Implantation Structures de données génériques Gestion des exceptions

3 Introduction L’objectif de cette partie du cours est de commencer à décrire des représentations des structures de base utilisées en informatique telles les listes. Ces derniers seront vus en termes de types abstraits. Un autre objectif recherché est de donner des exemples de séparations des représentations logiques à travers les TDA des implémentations physiques. Enfin, un dernier objectif est de décrire les outils du langage C++ qu’on aurait besoin pour implanter les structures de données dans notre cours.

4 Les listes Les listes sont des structures informatiques qui permettent de garder en mémoire des données en respectant un certain ordre: on peut ajouter, enlever ou consulter un élément en début ou en fin de liste, vider une liste ou savoir si elle contient un ou plusieurs éléments. La structure de liste particulièrement souple et dont les éléments sont accessibles à tout moment. Toute suite d’informations inscrites les unes après les autres est une liste. Exemple : liste d’étudiants, liste d’inventaire, liste des absents, …

5 Les listes Une liste est définie comme étant une suite ordonnée d’éléments. L’ordre signifie que chaque élément possède une position dans la liste. Une liste: structure récursive ( a (b ( c (d)))) a b c Une liste peut être vu comme une structure récursive : liste = élément + liste OU liste = vide

6 Un exemple de liste: une liste ordonnée
Liste ordonnée d’éléments (int) L = <8,1,5,4,6> L1 = 8, L2 = 1, L3 = 5, L4 = 4, L5 = 6 <8,1,5,4,6>  <8,1,4,6,5> Utilité?

7 Un exemple de liste: une liste ordonnée
Liste ordonnée d’éléments (int) L = <8,1,5,4,6> L1 = 8, L2 = 1, L3 = 5, L4 = 4, L5 = 6 <8,1,5,4,6>  <8,1,4,6,5> Utilité? liste de réquisitions Réq.#3 Réq.#2 Réq.#1 Réq.#1: 2000 chemises 1000 pantalons 1500 cravates ...

8 Un exemple de liste: une liste ordonnée
Liste ordonnée d’éléments (int) L = <8,1,5,4,6> L1 = 8, L2 = 1, L3 = 5, L4 = 4, L5 = 6 <8,1,5,4,6>  <8,1,4,6,5> Utilité? liste de réquisitions file d’attente 3 2 1

9 Un exemple de liste: une liste ordonnée
Liste ordonnée d’éléments (int) L = <8,1,5,4,6> L1 = 8, L2 = 1, L3 = 5, L4 = 4, L5 = 6 <8,1,5,4,6>  <8,1,4,6,5> Utilité? liste de réquisitions file d’attente Parcours d’un graphe 1 8 5 4 6

10 Un exemple de liste: une liste ordonnée
Liste ordonnée d’éléments (int) L = <8,1,5,4,6> L1 = 8, L2 = 1, L3 = 5, L4 = 4, L5 = 6 <8,1,5,4,6>  <8,1,4,6,5> Utilité? liste de réquisitions file d’attente Parcours d’un graphe 1 8 x 5 4 x 6

11 Un exemple de liste: une liste ordonnée
Liste ordonnée d’éléments (int) L = <8,1,5,4,6> L1 = 8, L2 = 1, L3 = 5, L4 = 4, L5 = 6 <8,1,5,4,6>  <8,1,4,6,5> Utilité? liste de réquisitions file d’attente Parcours d’un graphe 1 8 5 4 6

12 Opérateurs sur les listes
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6>

13 Opérateur: nombre d’éléments?
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6> L = 5

14 Opérateur: liste vide? L = <8,1,5,4,6> Non!
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6> Non!

15 Opérateur: appartenance
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6> 4  L? Oui! 9  L? Non!

16 Opérateur: accès L = <8,1,5,4,6> Manipulations (opérateurs): L
L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6> L1 = 8, L2 = 1, L3 = 5, L4 = 4, L5 = 6

17 Opérateur: rang (indice)
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6,1> 81, 12, 53, 44, 65, 90

18 Opérateur: ajout L = <8,1,5,4,6> L  L +1 9: <9,8,1,5,4,6>
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6> L  L +1 9: <9,8,1,5,4,6> L  L +2 9: <8,9,1,5,4,6> L  L +3 9: <8,1,9,5,4,6> L  L +4 9: <8,1,5,9,4,6> L  L +5 9: <8,1,5,4,9,6> L  L +6 9: <8,1,5,4,6,9> L  L +7 9: <>

19 Opérateur: retrait du rang
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6> L  -1 L: <1,5,4,6> L  -2 L: <8,5,4,6> L  -3 L: <8,1,4,6> L  -4 L: <8,1,5,6> L  -5 L: <8,1,5,4> L  -6 L: <8,1,5,4,6>

20 Opérateur: retrait d’élément
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6,1> L  L - 8: <1,5,4,6,1> L  L - 1: <8,5,4,6,1> L  L - 5: <8,1,4,6,1> L  L - 4: <8,1,5,6,1> L  L - 6: <8,1,5,4,1> L  L - 9: <8,1,5,4,6,1>

21 Opérateur: test d’égalité
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L  = <8,1,5,4,6> L’ = <8,1,4,6,5> Non!

22 Opérateur: inclusion stricte
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L  = <8,4,5> L’ = <8,1,4,6,5> Oui! L  = <8,1,4,6,5> L’ = <8,1,4,6,5> Non!

23 Opérateur: inclusion L = <8,4,5> L’ = <8,1,4,6,5>
Manipulations (opérateurs): L L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L  = <8,4,5> L’ = <8,1,4,6,5> Oui! L  = <8,1,4,6,5> L’ = <8,1,4,6,5> Oui!

24 Opérateur: listage L = <8,1,5,4,6> Manipulations (opérateurs):
L = ? (i.e., L = 0?) x  L? Li x = L? L  L +i x L  -i L L  L - x L = L’? L  L’? L  L’? lister L L = <8,1,5,4,6> 8,1,5,4,6

25 Opérateur: sous-liste
Autres opérateurs?

26 Opérateur: sous-liste
Autres opérateurs? sous-liste de L, de i, pour une longueur de n: L[i,n] L = <8,1,5,4,6> L[2,3] = <1,5,4>

27 Opérateur: concaténation
Autres opérateurs? sous-liste de L, de i, pour une longueur de n: L[i,n] concaténation de listes: L + L’ L = <8,1,5,4,6> L[2,3] = <1,5,4> L = <8,1,5,4,6> L’ = <1,9> L + L’ = <8,1,5,4,6,1,9>

28 Spécifications « langage C »
L  L +i x prototype de la fonction implantant l’opérateur: Liste ajouterListe(Liste l, TypeEl x, int i, int *err); préconditions  conditions devant être vraies au départ pour assurer le bon fonctionnement de l ’opérateur l ne doit pas être pleine et i  [1,|L|+1] postconditions  conditions étant vraies (observables) après l’application (correcte) de l’opérateur l contient x et *err = OK si les préconditions sont respectées l est inchangée sinon et *err contient: PAM si L est pleine, PERR si i  [1,|L|+1] valeur retournée en output de l’application de l ’opérateur: l mise à jour ou l inchangée en cas d'erreurs

29 Spécifications « C++ » prototype de la méthode implantant l’opérateur:
L  L +i x prototype de la méthode implantant l’opérateur: void ajouter(TypeEl x, int i) throw(range_error, length_error); préconditions  conditions devant être vraies au départ pour assurer le bon fonctionnement de l ’opérateur La liste ne doit pas être pleine et i  [1,|L|+1] postconditions  conditions étant vraies (observables) après l’application (correcte) de l’opérateur La liste contient x si les préconditions sont respectées La liste est inchangée sinon et : Exceptions  les exceptions lancées par la méthode lors d’un problème si L est pleine, si i  [1,|L|+1] valeur retournée en output de l’application de l ’opérateur: aucune

30 Spécifications version dOxygen
L  L +i x prototype de la méthode implantant l’opérateur: void ajouter(TypeEl x, int i) throw(range_error, length_error); /** * \brief Ajouter un nouvel élément dans la liste * * \pre il y a assez de mémoire pour ajouter l'élément x * \pre la position d'ajout, pos, est comprise entre 1 et |L|+1 * \post la liste comprend un élément de plus * \post la liste est inchangée sinon * \exception range_error si la position est erronée * \exception length_error si pas assez de mémoire */

31 Spécifications du type liste: -i
L -i L prototype: Liste enleverListe (Liste l, int i, int *err); préconditions: i  [1,|L|] postconditions: l est inchangée si i  [1,|L|] avec *err = PERR l contient un élément de moins, l’élément Li avec *err=OK, sinon valeur(s) retournée(s): l mise à jour ou inchangée en cas d'erreurs

32 Spécifications du type liste: -i
L -i L prototype: void enlever(int i) throw(range_error); préconditions: i  [1,|L|] postconditions: La liste contient un élément de moins, l’élément Li si la précondition n’est pas satisfaite La liste est inchangée si i  [1,|L|] sinon Exception: si la position est erronée valeur retournée: aucune

33 Spécifications du type liste: -i
dOxygen L -i L prototype: void enlever(int i) throw(range_error); /** * \brief Enlever l’élément en position i dans la liste * * \pre i est compris entre 1 et |L| * \post la liste comprend un élément de moins * \post la liste est inchangée sinon * \exception range_error si la position est erronée */

34 Spécifications du type liste: -
L  L - x prototype: Liste enleverElListe (Liste l, TypeEl x, int *err); préconditions: Aucune postconditions: l contient un élément x de moins (le premier rencontré), l inchangée si x  L et *err = OK valeur retournée: l inchangée si x n’appartenait pas à l l mise à jour sinon

35 Spécifications du type liste: -
L  L - x prototype: void enleverEl (TypeEl x); préconditions: Aucune postconditions: La liste contient un élément x de moins (le premier rencontré), inchangée si x  L Exception aucune valeur retournée:

36 Spécifications du type liste: -
dOxygen L  L - x prototype: void enleverEl (TypeEl x); /** * \brief EnleverEl dans la liste la première occurrence de x * * \post la liste comprend un élément de moins * \post la liste est inchangée si x  à la liste */

37 Spécification du type liste: Li
prototype: TypeEl elementListe(Liste l, int i, int *err); préconditions: i  [1,|L|] postconditions: l est inchangée avec *Err = OK l est inchangée et *Err = PERR si i [1,|L|] valeur(s) retournée(s): Une copie de Li si la précondition est respectée Une valeur quelconque sinon

38 Spécification du type liste: Li
prototype: TypeEl elementPos(int i) throw(range_error); préconditions: i  [1,|L|] postconditions: La liste est inchangée si i [1,|L|] La liste est inchangée sinon Exception : Si la position est erronée valeur(s) retournée(s): Une copie de Li si la précondition est respectée Une valeur quelconque sinon

39 Spécification du type liste: Li
dOxygen Li prototype: TypeEl elementPos(int i) throw(range_error);; /** * \brief retourner l’élément en position i dans la liste * * \pre i est compris entre 1 et |L| * \post la liste est inchangée * \post l’élément en position i est retournée, une valeur quelconque sinon * \exception range_error si la position i est erronée */

40 Implantation du type liste ordonnée
Implantation par tableau statique

41 Implantation du type liste ordonnée
Implantation par tableau La liste peut être implantée à l'aide d'un tableau. Dans ce cas, il faut prévoir une taille maximum pour le tableau. L'opération d'impression des éléments d'une liste et de recherche d'un élément se font en temps linéaire. La recherche du k-ième élément se fait O(1) i.e. en un temps constant. Cependant les insertions et les suppressions d'éléments sont plus coûteuses. Par exemple, l'insertion à la position 0 nécessite le déplacement de tous les éléments de la liste pour libérer la position 0. Par conséquent la création d'une liste à l'aide de n insertions successives à partir de la position 0 nécessite un temps en O(n2) (pourquoi?).

42 Implantation du type liste ordonnée
En langage C Implantation par tableau /******************************************************************** ModeleImplantationListe.h i.e. modèle d’implantation du type Liste ordonnée Version Janvier 2007 (c) IFT Structures de données ********************************************************************/ #ifndef _LISTEC__H #define _LISTEC__H #define MAX_LISTE 100 typedef enum {FAUX, VRAI} Bool; /*le type booléen*/ typedef int TypeEl; /* le type de base de la liste */ typedef struct { TypeEl tab[MAX_LISTE]; /* représentation physique de la liste */ int cpt; /* la cardinalité de la liste */ } Liste; /* le type liste ordonnée */ #endif

43 Création de listes En langage C { Liste l;
déclaration: Liste L1, L2; initialisation: L1 = initListe(&err); L2 = initListe(&err); Liste initListe(int * err) { Liste l; /*A: L’espace mémoire est suffisant.*/ l.cpt = 0; *err = OK; return l; }

44 Destruction de listes En langage C { … return l; } destruction:
detruireListe(L1, &err); detruireListe(L2, &err); Liste detruireListe(Liste l, int * err) { return l; }

45 Interface d’un type abstrait (invariable)
En langage C Interface du type Liste /******************************************************************** Liste.h i.e. interface du type Liste ordonnée Version Janvier 2007 (c) IFT Structures de données ********************************************************************/ #include "ModeleImplantationListe.h" #define OK 0 /* tout est correct */ #define LNI 1 /* liste non initialisée */ #define PAM 2 /* pas assez de mémoire*/ #define PERR 3 /* position erronée */ Liste initListe(int *err); /***************************************************************** prototype : Liste initListe(int *err) précondition : … etc..

46 Implémentation En langage C
/******************************************************************** Liste.c Version Janvier 2007 (c) IFT Structures de données ********************************************************************/ #include "Liste.h" Liste ajouterListe (Liste l, TypeEl x, int pos, int *err) { /* objectif: ajouter l'élément x à la liste l en position pos méthode: décaler vers la droite tous les éléments à partir de la fin de la liste, jusqu'à ce que pos soit atteint besoins: La liste l, l'élément x, l'indice d'insertion pos et MAX_LISTE, la taille maximale de la liste connu: MAX_LISTE entrée: l, x, pos sortie: La liste l mise à jour (si *err = OK), la liste l inchangée sinon. résultat: *err=OK si les pré sont respectées, PAM si pas assez de place, PERR si la position est erronée hypothèse: Pos est compris entre 1 et la taille de la liste + 1 (|L| + 1) inclusivement, il y a assez de place pour ajouter x. */

47 Implémentation En langage C
Liste ajouterListe (Liste l, TypeEl x, int pos, int *err) { … if (l.cpt >= MAX_LISTE) { /* La liste est pleine. */ *err = PAM; return l; } /*A: La liste n'est pas pleine */ if ((pos < 1) || (pos > (l.cpt + 1))) /* Les paramètre fournis sont invalides. */ *err = PERR; /*A: pos >= 1 et pos <= taille de la liste + 1 */ *err = OK; //etc... En langage C

48 Implantation du type liste ordonnée
En langage C++……

49 D’abord, quelques différences entre C++ et C en ce qui concerne le cours
malloc(sizeof(float)*25) free(x) realloc(x,sizeof(float)*25); typedef struct { // […] } MaStruct; void fonction(MaStruct *m,float x); Aucun équivalent pour « private: », il faut user de discipline. float f(float a, int x, int *err) { if(x<a) { *err=PROBLEME; return 0.0f; } // […] } int x; for(x=0;x<2;x++) new float[25] delete x ou delete[] x Pas d’équivalent pour « realloc » struct MaStruct { void fonction(float x); }; Possibilité de rendre des membres privés à l’aide de « private: » float f(float a, int x) { if(x<a) throw PROBLEME; // […] } for(int x=0;x<2;x++)

50 D’abord, quelques différences entre C++ et C en ce qui concerne le cours
typedef struct { float x[100]; int n; } Nombres; CodeErreur initNombres(Nombres *n); CodeErreur ajoutNombres(Nombres *n , float nouv_nbr); // etc. struct Nombres { Nombres(); void ajout(float nouv_nbr); // etc. private: float x[100]; int n; };

51 D’abord, quelques différences entre C++ et C en ce qui concerne le cours
typedef enum { OK, Erreur } CodeErr; typedef struct { int matricule,nb_cours,age; char nom[50]; } Etudiant; Etudiant etudiants[40000]; int n; } Universite; CodeErr initUniversite(Universite *u); CodeErr ajoutUniversite(Universite *u, Etudiant et); int trouve_age(const Universite *u, int matricule); void detruitUniversite(Universite *u); struct Etudiant { public: int matricule,nb_cours,age; char nom[50]; }; struct Universite Universite(); void ajout(Etudiant et); int trouve_age(int matricule) const; ~Universite(); private: Etudiant etudiants[40000]; int nb_etudiants;

52 D’abord, quelques différences entre C++ et C en ce qui concerne le cours
Universite::Universite() { n=0; } void Universite::ajout(Etudiant et) if(n==40000) throw runtime_error(‘’L’université est pleine!’’); etudiants[n++]=et; int Universite::trouve_age(int matricule) const for(int i=0;i<n;i++) if(etudiants[i].matricule==matricule) return etudiants[i].age; return -1; // Convention pour matricule introuvable. Universite::~Universite() CodeErr initUniversite(Universite *u) { u->n=0; return OK; } CodeErr ajoutUniversite(Universite *u, Etudiant et) if(u->n==40000) return Erreur; u->etudiants[u->n++] = et; int trouve_age(const Universite *u, int matricule) int i; for(i=0;i<u->n;i++) if(u->etudiants[i].matricule==matricule) return u->etudiants[i].age; return -1; // Convention pour matricule introuvable. void detruitUniversite(Universite *u) C++ C

53 Encapsulation. struct (C) vs classe (C++)
//Fichier ModeleImplantationListe.h #ifndef _LISTEC__H #define _LISTEC__H #define MAX_LISTE 100 typedef enum {FAUX, VRAI} Bool; typedef struct { int tab[MAX_LISTE]; int cpt; } Liste; #endif //Fichier Liste.h #include "ModeleImplantationListe.h" #include "CodesErreur.h" Liste initListe(int * err); /* */ int tailleListe(Liste l, int *err); Bool estVideListe(Liste l, int *err); Liste ajouterListe(Liste l, int x, int pos, int *err); // etc.. Version de base // Fichier Liste.h #include <iostream> using namespace std; #ifndef _LISTEC__H #define _LISTEC__H #define MAX_LISTE 100 class Liste { private: int tab[MAX_LISTE]; int cpt; public: Liste(); //constructeur ~Liste(); //destructeur void ajouter (int x, int pos); int taille() const ; bool estVide() const; //etc… }; #endif

54 Implantation du type liste ordonnée
Note 1 Remarquez que le mot clé const est utilisé à la fin des déclarations de fonction membres de la classe Liste en mode lecture seule, à savoir taille () et estVide(). Afin de mieux protéger un programme, il y a tout intérêt à déclarer comme constantes les fonctions qui ne sont pas censées modifier l’état des objets auxquels elles sont liés. On bénéficiera ainsi d’une aide supplémentaire du compilateur qui empêchera tout ajout de code modifiant l’état de l’objet dans la fonction.

55 Implantation de la classe Liste en C++
//Liste.cpp #include "Liste.h" Liste::Liste() { cpt = 0; } bool Liste::estVide() const return taille()==0; Liste:: ~Liste() cpt=0; //Note.. int Liste::taille() const return cpt; #include "Liste.h "   void Liste::ajouter (int x, int pos) { if(cpt==MAX_LISTE) return; if (pos < 1 || pos > taille() +1) return; pos--; for (i = (cpt - 1); i >= pos; i--) tab[i+1] = tab[i]; } tab[pos] = x; cpt++;

56 Utilisation de la classe Liste
//Main.cpp #include "Liste.h" int main() { Liste l; //appel automatique du constructeur l.ajouter(1,1); l.ajouter(2,2); l.ajouter(3,3); if(l.estVide()) cout << "liste vide" << endl; else cout << "liste non vide" << endl; cout << l.taille() << endl; l.~Liste(); //destruction de la liste, inutile… // etc.. return 0; }

57 Définition de la classe Liste en C++ (version 2)
#ifndef _LISTEC__H #define _LISTEC__H #include <iostream> using namespace std; #define MAX_LISTE 5 // Le type Liste class Liste{ public: Liste(); //constructeur ~Liste(); //destructeur Liste(const Liste &); //constructeur de copie Liste& operator = (const Liste&); // surcharge de l’opérateur = void ajouter(int x, int pos); bool estVide() const; int taille() const; friend ostream& operator << (ostream&, const Liste& p); Liste& operator = (const Liste&); private: int tab[MAX_LISTE]; int cpt; }; #endif Constructeur de copie Surcharge op. =

58 Définition de la classe Liste en C++ (version 2)
Constructeur de copie Le constructeur par copie est une méthode implicite dans toute classe. Cette méthode est appelée automatiquement dans les opérations suivantes : Création et initialisation d ’une nouvelle instance X I2=I1; X I2(I1); passage d ’un argument par valeur retour d ’une fonction return (I); // une copie de I est retournée

59 Définition de la classe Liste en C++ (version 2)
Constructeur de copie class Liste { public : Liste (const Liste&); // constructeur par copie ... }; Par défaut, cette méthode implicite réalise une copie des valeurs qui correspondent à la section private de la classe. Si l ’implantation d ’un objet est dynamique le constructeur par copie, réalisera par défaut une copie de pointeur. ==> Surcharger cet opérateur afin qu’il crée un vrai clone de l ’instance qui le déclenche.

60 Implémentation (version 2)
#include "Liste.h" int main() { //on crée une instance d'une liste Liste l; l.ajouter(1,1); //ajout de 1 en pos =1 //... //copie de l'appel du constructeur de copie Liste l1(l); //Affichage de la copie cout << l1 << endl; return 0; } Constructeur de copie Liste :: Liste (const Liste& l) { cpt = l.cpt; for (int i=0; i<cpt;i+=1) tab[i]=l.tab[i]; } ostream& operator << (ostream& f, const Liste& l){ for (int i=0; i<l.cpt;i++) f << l.tab[i]<<" "; return f;

61 Définition de la classe Liste en C++ (version 2)
Surcharge de l’opérateur = L ’opérateur d ’affectation est une méthode implicite dans toute classe. Par défaut, il réalise une copie des valeurs qui correspondent à la section private de la classe. Liste l1; ... l1.tab Liste l2; l2=l1; Problème : Toute modification du tableau des entiers dans la liste l1 se répercute dans la liste l2 (et inversement) l2.tab

62 Définition de la classe Liste en C++ (version 2)
Surcharge de l’opérateur = Pour réaliser une vraie copie de pile par affectation, il faut surcharger l ’opérateur implicite. Liste l1; ... l1.tab Liste l2; l2=l1; l2.tab

63 Définition de la classe Liste en C++ (version 2)
Surcharge de l’opérateur = class Liste { public: Liste operator = (const Liste&); // opérateur d ’affectation l1 = l2 <=> l1.operator = (l2); Le comportement habituel de l’opérateur = autorise à enchaîner les affectations : l1=l2=l3; => la fonction retourne une référence et l ’argument est une référence.

64 Implémentation (version 2)
#include "Liste.h" int main() { //on crée une instance d'une liste Liste l; l.ajouter(1,1); //ajout de 1 en pos =1 //... Liste l1; l1 = l; // appel de l’op. = surchargé //Affichage de la copie cout << l1 << endl; return 0; } Surcharge de l’op. = Liste& operator = (const Liste&){ cpt = l.cpt; for (int i=0; i<cpt;i+=1) tab[i]=l.tab[i]; return (*this); //retourner : une référence sur // ’objet courant }

65 Forme canonique de Coplien
Remarque On dit qu'une classe est sous forme canonique de Coplien si elle contient les éléments suivants : template <typename T> class Liste { public: Liste(const int = MAX_LISTE) throw(bad_alloc); // constructeur Liste(const Liste&) throw(bad_alloc); // constructeur de copie ~Liste(); // destructeur Liste<T>& operator = (const Liste<T>&) throw (bad_alloc); //surcharge de = //… On fera de sorte que toutes les classes que nous Implanterons auront ces méthodes au minimum.

66 Définition de la classe Liste en C++ (version 3.1)
#include <iostream> using namespace std; #pragma warning( disable : 4290 ) #define MAX_LISTE 5 // Le type Liste class Liste{ public: Liste(); //constructeur ~Liste(); //destructeur Liste(const Liste&); //constructeur de copie void ajouter(int x, int pos) throw(int); // lancement d’un int bool estVide() const; int taille() const; friend ostream& operator << (ostream&, const Liste& p); Liste& operator = (const Liste&); private: int tab[MAX_LISTE]; int cpt; }; Gestion des exceptions Usage d’un int

67 Implémentation (version 3.1)
int main() { Liste l; try //on essaie un ajout{ l.ajouter(1,1); l.ajouter(2,2); l.ajouter(4,8); // erreur.. //… } catch(int& code) { cerr << "ERREUR: " << code << endl; return 0; } .... void Liste::ajouter (int x, int pos) throw(int) { if (cpt==MAX_LISTE) throw 1; if (pos < 1 || pos > this->taille() +1) throw 2 ; //… }

68 Définition de la classe Liste en C++ (version 3.2)
#include <iostream> using namespace std; #include <stdexcept> #pragma warning( disable : 4290 ) #define MAX_LISTE 5 // Le type Liste class Liste{ public: Liste(); //constructeur ~Liste(); //destructeur Liste(const Liste&); //constructeur de copie void ajouter(int x, int pos) throw(out_of_range, length_error); bool estVide() const; int taille() const; friend ostream& operator << (ostream&, const Liste& p); Liste& operator = (const Liste&); private: int tab[MAX_LISTE]; int cpt; }; Gestion des exceptions Usage d’une classe de la librairie stdexcept

69 Implémentation (version 3.2)
int main() { Liste l; try //on essaie un ajout{ l.ajouter(1,1); l.ajouter(2,2); l.ajouter(4,8); // erreur.. //… } catch(exception& e) cerr << "ERREUR: " << e.what() << endl; return 0; } .... void Liste::ajouter (int x, int pos) throw(out_of_range, length_error); { if (cpt==MAX_LISTE) throw length_error("Ajouter:La liste est pleine"); if (pos < 1 || pos > this->taille() +1) throw out_of_range("Ajouter:Position d'ajout erronée"); //… }

70 Définition de la classe Liste en C++ (version 3.3)
#include <iostream> using namespace std; #pragma warning( disable : 4290 ) #define MAX_LISTE 5 // Le type Liste class Liste{ public: Liste(); //constructeur ~Liste(); //destructeur Liste(const Liste&); //constructeur de copie void ajouter(int x, int pos) throw(Erreur); bool estVide() const; int taille() const; friend ostream& operator << (ostream&, const Liste& p); Liste& operator = (const Liste&); private: int tab[MAX_LISTE]; int cpt; }; Gestion des exceptions Usage d’une classe Erreur

71 Définition de la classe Liste en C++ (version 3.3)
Suite.. class Erreur: public exception{ public: Erreur(int numero=0,std::string phrase="", int niveau=0) throw() :m_numero(numero),m_phrase(phrase),m_niveau(niveau){} virtual const char* what() const throw(){ return m_phrase.c_str();} int getNiveau() const throw(){ return m_niveau;} int getNumero() const throw(){ return m_numero;} virtual ~Erreur() throw(){} private: int m_numero; //Numéro de l'erreur string m_phrase; //Description de l'erreur int m_niveau; //Niveau de l'erreur };

72 Implémentation (version 3.3)
int main() { Liste l; try //on essaie un ajout{ l.ajouter(1,1); l.ajouter(2,2); l.ajouter(4,8); // erreur.. //… } catch(const Erreur& e) cerr<< "ERREUR: "<< e.what()<<endl; cerr<<"Niveau: "<<e.getNiveau()<<endl; cerr <<"Numero: "<<e.getNumero()<<endl; return 0; } .... void Liste::ajouter (int x, int pos) throw(out_of_range, length_error); { if (cpt==MAX_LISTE) throw Erreur(1, «Ajouter:La liste est pleine", 2); if (pos < 1 || pos > this->taille() +1) throw Erreur(2, « Ajouter: Position d'ajout erronée",2); //… }

73 Gestion des exceptions
Note 2 Il faut savoir que vous n'êtes pas le seul à lancer des exceptions. Certaines fonctions standards lancent elles aussi des exceptions. Toutes les exceptions lancées par les fonctions standards dérivent de la classe exception, ce qui permet avec un code générique de rattraper toutes les erreurs qui pourraient potentiellement arriver. Exemple: catch(const std::exception& e) { std::cerr << "ERREUR: " << e.what() << std::endl; } Ceci est possible grâce au polymorphisme. On attrape un objet de type std::exception, mais grâce aux fonctions virtuelles et à la référence (les deux ingrédients), c'est la fonction what() de la classe fille qui sera appelée, ce qui est justement ce que l'on souhaite. :)

74 Gestion des exceptions
Note 3 La bibliothèque standard peut lancer 5 types d'exceptions différents résumés dans le tableau suivant : Nom de la classe Description bad_alloc Lancée s'il se produit une erreur lors d'un new. bad_cast Lancée s'il se produit une erreur lors d'un dynamic_cast. (On verra plus tard ce que c'est) bad_exception Lancée si aucun catch ne correspond à un objet lancé. bad_typeid Lancée s'il se produit une erreur lors d'un typeid.(On verra plus tard ce que c'est) ios_base::failure Lancée s'il se produit une erreur avec un flux.

75 Gestion des exceptions
#include <stdexcept> Le fichier stdexcept contient 9 classes d'exceptions séparées en 2 catégories, les exceptions "logiques" (logic errors) et les exceptions "d'exécution" (runtime errors). Toutes les exceptions présentées dérivent de la classe std::exception et possèdent un constructeur prenant en argument une chaîne de caractère permettant de décrire le problème.

76 Gestion des exceptions
#include <stdexcept> suite.. Nom de la classe Catégorie Description domain_error logique Lancée s'il se produit une erreur de domaine mathématique. invalid_argument logique Lancée si un des arguments d'une fonction est invalide. length_error logique Lancée si un objet aura une taille invalide. Par exemple si la classe Pile vue précédemment a une taille dépassant la taille de la mémoire. out_of_range logique Lancée si il y a une erreur avec un indice. Par exemple si on essaye d'accéder à une case inexistante d'un tableau. logic_error logique Lancée lors de n'importe quel autre problème de logique du programme. range_error exécution Lancée lors d'une erreur de domaine à l'exécution. overflow_error exécution Lancée si il y a une erreur d'overflow. underflow_error exécution Lancée si il y a une erreur d'underflow. runtime_error exécution Lancée pour tout autre type d'erreur non-prévue survenant à l'exécution. Sinon, vous ne savez pas quoi choisir, prenez simplement runtime_error.

77 Programmation générique
Introduction La classe Liste de tout à l’heure se présentait comme suit : class Liste{ public: private: int tab[MAX_LISTE]; }; Si l’on veut une liste de double? + c’est exactement le même code sauf qu’il faut remplacer le type de la données pouvant être stockée dans un tableau + duplication de code !!

78 Définition de la classe Liste en C++ (version 4)
#include <iostream> using namespace std; #pragma warning( disable : 4290 ) template <typename T> class Liste{ public: Liste(); //constructeur ~Liste(); //destructeur Liste(const Liste&); //constructeur de copie void ajouter(T x, int pos)throw(out_of_range, length_error); bool estVide() const; int taille() const; friend ostream & operator << (ostream & f, const Liste & l){ for (int i=0; i<l.cpt;i++) f << l.tab[i]<<" "; return f; } private: static const int MAX_LISTE = 5; //Remplace le #define MAX_LISTE T tab[MAX_LISTE]; int cpt; }; #include "Liste.inl" Liste générique

79 Définition de la classe Liste en C++ (version 4)
#define MAX_LISTE 5 template <typename T> class Liste{ public: Liste(); //constructeur ~Liste(); //destructeur void ajouter(T x, int pos)throw(out_of_range, length_error); //… private: T tab[MAX_LISTE]; int cpt; }; Paramètre générique Formel

80 Définition de la classe Liste en C++ (version 4)
template <typename T, in max = 100> class Liste{ public: Liste(); //constructeur ~Liste(); //destructeur void ajouter(T x, int pos)throw(out_of_range, length_error); //… private: T tab[max]; int cpt; }; Paramètres génériques Formels

81 Implémentation (version 4)
Liste.inl #include "Liste.h" template <typename T> Liste<T>::Liste() { cpt = 0; } bool Liste<T>::estVide() const return taille()==0; template <typename T> void Liste<T>::ajouter (T x, int pos) throw(out_of_range, length_error) { this->tab[pos] = x; this->cpt++; }

82 Utilisation de la classe Liste générique
int main() { Liste<int> l; // ou Liste<int, 100> try{ l.ajouter(1,1); //ajout de 1 en pos =1 l.ajouter(2,2); //ajout de 2 en pos =2 l.ajouter(3,3); //ajout de 3 en pos =3 l.ajouter(4,8); //erreur, position erronée l.ajouter(4,1); //ajout de 4 en pos =1 l.ajouter(5,3); //ajout de 5 en pos =3 l.ajouter(6,6); //erreur, liste pleine } catch(exception &e){ cerr << "ERREUR: " << e.what() << endl; return 0; Paramètre générique effectif

83 Limitations d’une implantation par tableau
private : int cpt; T tab[max]; // implantation dans un tableau }; // statique il faut prévoir le pire cas si grandes fluctuations  gaspille d’espace limitation majeure en ajout d’éléments besoins variables? allocation dynamique (de mémoire) Utilité des pointeurs et objets pointées Cours de la semaine prochaine


Télécharger ppt "Structures de données IFT-2000"

Présentations similaires


Annonces Google