Structures de données IFT-2000 Abder Alikacem Pointeurs, références et gestion dynamique de la mémoire. QQ éléments techniques du C++. Semaine 2..suite.

Slides:



Advertisements
Présentations similaires
La boucle for : init7.c et init71.c
Advertisements

C++ 6ème cours Patrick Reuter maître de conférences
La classe String Attention ce n’est pas un type de base. Il s'agit d'une classe défini dans l’API Java (Dans le package java.lang) String s="aaa"; // s.
Cours n° 8 Conception et Programmation à Objets
C.
Chap. 1 Structures séquentielles : listes linéaires
Leçon 3 : Héritage IUP 2 Génie Informatique
Principes de programmation (suite)
Structures de données linéaires
Structures de données et algorithmes – C5 Maria-Iuliana Dascalu, PhD
Les méthodes en java Une méthode est un regroupement d’instructions ayant pour but de faire un traitement bien précis. Une méthode pour être utilisée.
Leçon 6 : Structures de données dynamiques IUP 2 Génie Informatique Méthode et Outils pour la Programmation Françoise Greffier.
Bibliothèque standard du C++
8PRO100 Éléments de programmation Allocation dynamique de la mémoire.
IFT-2000: Structures de Données Listes chaînées Dominic Genest, 2009.
Introduction au paradigme objet Concepts importants surcharge (overload) redéfinition (override) Définition d’une classe Définition des attributs.
Les Classes les structures en C (struct) regroupent des variables : structuration de l'analyse mais problèmes de cohérence problèmes de sécurité d'accès.
Quest-ce quune classe dallocation? Une classe dallocation détermine la portée et la durée de vie dun objet ou dune fonction.
Standard Template Library (STL)
Structures de données IFT-2000
Structures de données IFT Abder Alikacem La classe vector Édition Septembre 2009 Département dinformatique et de génie logiciel.
Les pointeurs Modes d’adressage de variables. Définition d’un pointeur. Opérateurs de base. Opérations élémentaires. Pointeurs et tableaux. Pointeurs et.
IFT-2000: Structures de données Plan de cours Théorie du contrat Types abstraits Dominic Genest, 2009.
IFT-2000: Structures de données
IFT-10541A : Hiver 2003 Semaine 1 : Type de données abstrait.
Structures de données IFT-2000
Structures de données IFT Abder Alikacem La classe string Département dinformatique et de génie logiciel Édition Septembre 2009 Département dinformatique.
Structures de données IFT-2000
Structures de données IFT-2000
Structures de données IFT-2000 Abder Alikacem Standard Template library Édition Septembre 2009 Département dinformatique et de génie logiciel.
Structures de données IFT Abder Alikacem Gestion des exceptions Département dinformatique et de génie logiciel Édition Septembre 2009.
Structures de données IFT-2000
Programme de baccalauréat en informatique Programmation Orientée Objets IFT Thierry EUDE Module 7 : Classes et fonctions paramétrables Département.
Présentation Structures de Données et TDA
Sixième cours Les chaînes de caractères et le passage de paramètres par référence Passage de paramètres par référence String.h.
COURS DE PROGRAMMATION ORIENTEE OBJET :
Standard Template Library
Leçon 1 : notion dobjet IUP Génie Informatique Besançon Méthode et Outils pour la Programmation Françoise Greffier Université de Franche-Comté.
Structures de données IFT-2000
Structures de données IFT-10541
Structures de données IFT-2000 Abder Alikacem La récursivité Semaine 5 Département dinformatique et de génie logiciel Édition Septembre 2009.
Structures de données IFT-2000 Abder Alikacem Semaine 11 Gestion des arbres binaires de tri et de recherche. Les arbres cousus. Les arbres n-aires Département.
Structures de données IFT-2000 Abder Alikacem Retour sur les listes ordonnées Département dinformatique et de génie logiciel Édition Septembre 2009.
Plan cours La notion de pointeur et d’adresse mémoire.
Structures de données IFT-2000
Structures de données IFT-2000
Structures de données IFT-2000 Abder Alikacem Introduction Semaine 1 Département d’informatique et de génie logiciel Édition Septembre 2009.
LES PILES ET FILES.
La notion de type revisitée en POO
1 Structures des données. 2  Le tableau permettait de désigner sous un seul nom un ensemble de valeurs de même type, chacune d'entre elles étant repérée.
Cours C++ Fonctions Surcharge d’opérateurs Passage d’arguments
Tutorat en bio-informatique
Tutorat en bio-informatique Le 14 novembre Au programme… Les objets –Propriétés (attributs) –Constructeurs –Méthodes.
ETNA – 1ème année Guillaume Belmas –
Les classes et les objets Les données finales class A { … private final int n = 20 ; // la valeur de n est définie dans sa déclaration … } class A { public.
Classe 1 CSI2572 Autres modificateurs de déclaration de variables: & volatile & register & static & auto & extern & const volatile Indique au compilateur.
Liste Une liste est une séquence d’éléments. Concept important: Chaque élément possède une position dans la liste. Notation: De quelles opérations a-t-on.
Conception de Programmes - IUT de Paris - 1ère année Quelques éléments du langage C++ Les références La surcharge de fonctions Les fonctions «
8PRO107 Éléments de programmation Les adresses et les pointeurs.
8PRO107 Éléments de programmation Les tableaux. Étude de cas 1 Description du problème : Lire une liste d’entiers et l’afficher d’abord dans le même ordre.
PRO-1027 Programmation Scientifique en C
Langage de Programmation Orientée Objet : C++
1 Listes des méthodes de la classe string, et exemples.
Structures de données IFT-2000 Abder Alikacem Laboratoire #1 Département d’informatique et de génie logiciel Édition Septembre 2009.
Exception Handling "Unfortunately, it's almost accepted practice to ignore error conditions, as if we're in a state of denial about errors." Bruce Eckel.
C++ BY AURÉLIEN MODULO MARION. PLAN DES TROIS PRÉSENTATIONS C++ avancé C++ orienté objet Bases de C++
Informatique 2A Langage C 5ème séance. Déroulement de la séance 5 1 ère partie Étude des chaînes de caractères 2 ème partie Les structures 3.
Transcription de la présentation:

Structures de données IFT-2000 Abder Alikacem Pointeurs, références et gestion dynamique de la mémoire. QQ éléments techniques du C++. Semaine 2..suite et fin Département d’informatique et de génie logiciel Édition Septembre 2009

Plan  Gestion dynamique de la mémoire  Tableaux dynamiques, tableaux à une et plusieurs dimensions  Pointeurs sur des objets et chaînage de la mémoire  Listes simplement chaînées

Chaînes de caractères dynamiques Puisqu’une chaîne de caractères n’est finalement qu’un tableau de caractères, on peut en faire une version dynamique. #include … char *x; x = new(nothrow) char[strlen(‘’Bonjour’’)+1]; if(!x) { // Erreur…l’allocation a échoué } //Si l’allocation a réussi, la ligne suivante peut se faire… strcpy(x, ’’Bonjour’’); cout << x << endl; delete[] x; À ne pas oublier!

Chaînes de caractères dynamiques  Puisqu’une chaîne de caractères est un tableau, si on veut faire un tableau de chaînes de caractères, on a alors à faire à un tableau de tableaux.  On a le choix entre:  Un tableau statique de chaînes de caractères statiques  Un tableau dynamique de chaînes de caractères statiques  Un tableau statique de chaînes de caractères dynamiques  Un tableau dynamique de chaînes de caractères dynamiques

Les tableaux à plusieurs dimensions  Comme pour les tableaux de chaînes de caractères, l’utilisation de n’importe quel tableau à plusieurs dimensions implique un choix « dynamique » ou « statique » pour chaque dimension.  Par exemple, un tableau de « int » à trois dimensions peut être déclaré de 8 façons différentes: 1.int x[2][3][4]; // 2 tableaux de 3 tableaux de 4 ints. 2.int *x[2][3]; //2 tableaux de 3 tableaux d’un nombre variable de ints. 3.int **x[2]; // 2 tableaux de nombres variables de tableaux à taille variable de ints. 4.int ***x; // Nombre variable de tableaux à tailles variables de tableaux à tailles variables de ints. 5.int (*x)[3][4]; // Nombre variable de tableaux de 3 par 4 ints. 6.int (**x)[4]; // Nombre variable de tableaux à tailles variables de 4 ints. 7.int (*x[2])[4]; // 2 tableaux d’un nombre variable de tableaux de 4 ints. 8.int *(*x)[3]; // Un nombre variables de tableaux de 3 tableaux de nombres variables de int.

Allocation dynamique de la mémoire Obtenir des variables (de la mémoire) selon les besoins de l’application gestion dynamique de la mémoire mais: variables sans noms! => accès par pointeur debut Utilisation des pointeurs Liste simplement chaînée

Allocation de mémoire obtenir des objets au besoin: debut = new Noeud; réserve de l’espace sur le « heap » (tas) retourne un pointeur sur un objet un Noeud lance une exception si plus de mémoire debut el suivant taspile struct Noeud { int el; /* l’information à stocker */ Noeud*suivant; } ; Noeud *debut, *courant, *nouveau;

obtenir les objets au besoin: debut = new Noeud; réserve de l’espace sur le « heap » (tas/monceau) retourne un pointeur sur un objet Noeud lance une exception si plus de mémoire debut el suivant taspile Allocation de mémoire struct Noeud { int el; /* l’information à stocker */ Noeud*suivant; } ; Noeud *debut, *courant, *nouveau;

obtenir les objets au besoin: debut = new Noeud; réserve de l’espace sur le « heap » (tas) retourne un pointeur sur un objet Noeud lance une exception si plus de mémoire debut->el = 3; debut->suivant = 0; Allocation de mémoire debut el suivant taspile 3 struct Noeud { int el; /* l’information à stocker */ Noeud*suivant; } ; Noeud *debut, *courant, *nouveau;

debut el suivant taspile 3 obtenir les objets au besoin: debut = new Noeud; réserve de l’espace sur le « heap » (tas) retourne un pointeur sur un objet Noeud lance une exception si plus de mémoire debut->el = 3; debut->suivant = 0; Allocation de mémoire struct Noeud { int el; /* l’information à stocker */ Noeud*suivant; } ; Noeud *debut, *courant, *nouveau;

Libération de mémoire obtenir les objets au besoin: debut = new Noeud; réserve de l’espace sur le « heap » (tas) retourne un pointeur sur un objet Noeud lance une exception si plus de mémoire debut->el = 3; debut->suivant = 0; delete debut; debut = 0; /* et non l’inverse */ debut el suivant taspile 3 x

Libération de mémoire debut el suivant taspile 3 x obtenir les objets au besoin: debut = new Noeud; réserve de l’espace sur le « heap » (tas) retourne un pointeur sur un objet Noeud lance une exception si plus de mémoire debut->el = 3; debut->suivant = 0; delete debut; debut = 0; /* et non l’inverse */

debut = new Noeud; debut->el = 3; debut->suivant = 0; debut = new Noeud; debut el suivant taspile 3 Chaînage d’objets

debut el suivant taspile el suivant 3 debut = new Noeud; debut->el = 3; debut->suivant = NULL; debut = new Noeud; //non, il faut utiliser un autre //pointeur que debut, le sommet de la liste chaînée en //construction, pour poursuivre la //construction de la liste chaînée Chaînage d’objets Erreur à éviter car, entre autres, on a créé un déchet (memory leack)

/* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau; debut taspile nouveau courant Chaînage d’objets

debut el suivant taspile nouveau courant /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau; Chaînage d’objets

debut el suivant taspile 3 nouveau courant /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau; Chaînage d’objets

debut el suivant taspile 3 nouveau courant Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 courant nouveau Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant 3... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant 3... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant 3... el suivant Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant 3... el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant 3... el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant 3... el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

debut el suivant taspile 3 nouveau courant el suivant 3... el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau;

Constructeur!! Chaînage d’objets /* pour le premier élément */ debut = new Noeud; debut->el = 3; debut->suivant = 0; courant = debut; /* pour les autres éléments */ nouveau = new Noeud; nouveau->el =...; nouveau->suivant = 0; courant->suivant = nouveau; courant = nouveau; On est en présence ici de 2 parties de code identiques, on va les rassembler dans une fonction/méthode appelée constructeur.

struct Noeud { int el; // l’information à stocker Noeud*suivant; // lien avec le suivant Noeud (const int& data_item, Noeud* next_ptr = 0) : el(data_item), suivant(next_ptr) {} //constructeur } ; Chaînage d’objets

/* pour le premier élément */ debut = new Noeud(3); courant = debut; /* pour les autres éléments */ nouveau = new Noeud(…); courant->suivant = nouveau; courant = nouveau; debut taspile nouveau courant Chaînage d’objets

debut taspile nouveau courant el suivant 33 Chaînage d’objets /* pour le premier élément */ debut = new Noeud(3); courant = debut; /* pour les autres éléments */ nouveau = new Noeud(…); courant->suivant = nouveau; courant = nouveau;

debut taspile nouveau courant el suivant 33 Chaînage d’objets /* pour le premier élément */ debut = new Noeud(3); courant = debut; /* pour les autres éléments */ nouveau = new Noeud(…); courant->suivant = nouveau; courant = nouveau;

debut taspile nouveau courant el suivant 33 el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud(3); courant = debut; /* pour les autres éléments */ nouveau = new Noeud(…); courant->suivant = nouveau; courant = nouveau;

debut taspile nouveau courant el suivant 33 el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud(3); courant = debut; /* pour les autres éléments */ nouveau = new Noeud(…); courant->suivant = nouveau; courant = nouveau;

debut taspile nouveau courant el suivant 33 el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud(3); courant = debut; /* pour les autres éléments */ nouveau = new Noeud(…); courant->suivant = nouveau; courant = nouveau;

debut taspile nouveau courant el suivant 33 el suivant... Chaînage d’objets /* pour le premier élément */ debut = new Noeud(3); courant = debut; /* pour les autres éléments */ nouveau = new Noeud(…); courant->suivant = nouveau; courant = nouveau; Liste simplement chaînée

Chaînage d’objets  Le C++, comme le C, n'offre pas de mécanisme de récupération automatique de la mémoire (garbage collecting). Attention donc aux déchets (memory leack).  Allocation et libération des ressources : la responsabilité du programmeur et attention aux références pendantes!  Pour gérer les ressources à l'intérieur des classes, il faut correctement implanter certaines fonctions/méthodes pour ne pas se retrouver avec des problèmes. Nous en reparlerons. Rappels et mise en garde!

Copies profondes et copies de surface  Lorsqu’une structure a un membre qui est un pointeur, copier le contenu de la structure d’une variable à une autre avec l’opérateur « = » ne va que copier le contenu du pointeur en question. Ainsi, les deux variables partageront un même espace-mémoire.  Par exemple, si on fait delete sur l’une des copies, alors la deuxième copie n’est plus utilisable non plus et fera planter le logiciel. Noeud n1(10), n2; n2 = n1; //  Dangereux!  Nous verrons bientôt comment régler ce problème par le biais de la surcharge de l’opérateur d’affectation.

Structures de données IFT-2000 Abder Alikacem Les listes ordonnées Programmation générique en C++ Semaine 3 Département d’informatique et de génie logiciel Édition Septembre 2009

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

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

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

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

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

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

Manipulations (opérateurs):  L  L =  ? (i.e.,  L  = 0?) x  L? L i x = L ? L  L + i x L  - i L L  L - x L = L’? L  L’? L  L’? lister L L = Opérateurs sur les listes

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

Opérateur: liste vide? Manipulations (opérateurs):  L  L =  ? L =  ? (i.e.,  L  = 0?) x  L? L i x = L ? L  L + i x L  - i L L  L - x L = L’? L  L’? L  L’? lister L L = Non!

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

Manipulations (opérateurs):  L  L =  ? (i.e.,  L  = 0?) x  L? L i L i x = L ? L  L + i x L  - i L L  L - x L = L’? L  L’? L  L’? lister L L = L 1 = 8, L 2 = 1, L 3 = 5, L 4 = 4, L 5 = 6 Opérateur: accès

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

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

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

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

Manipulations (opérateurs):  L  L =  ? (i.e.,  L  = 0?) x  L? L i x = L ? L  L + i x L  - i L L  L - x L = L’? L = L’? L  L’? L  L’? lister L L = L’ = Non! Opérateur: test d’égalité

Opérateur: inclusion stricte Manipulations (opérateurs):  L  L =  ? (i.e.,  L  = 0?) x  L? L i x = L ? L  L + i x L  - i L L  L - x L = L’? L  L’? L  L’? L  L’? lister L L = L’ = Oui! L = L’ = Non!

Opérateur: inclusion Manipulations (opérateurs):  L  L =  ? (i.e.,  L  = 0?) x  L? L i x = L ? L  L + i x L  - i L L  L - x L = L’? L  L’? L  L’? L  L’? lister L L = L’ = Oui! L = L’ = Oui!

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

Autres opérateurs sous-liste de L, de i, pour une longueur de n: L[i,n] concaténation de listes: L + L’ L = L[2,3] = L = L’ = L + L’ = Opérateurs: sous-liste et concaténation

Implantation du type liste ordonnée 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(n 2 ). Implantation par tableau statique

D’abord, quelques différences entre C++ et C C printf, scanf 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++) C++ cout > 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++)

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.. // Fichier Liste.h #include using namespace std; #ifndef _LISTEC__H #define _LISTEC__H class Liste { public: Liste(); //constructeur ~Liste(); //destructeur void ajouter (int x, int pos); int taille() const ; bool estVide() const; //etc… private: static const int MAX_LISTE = 100; int tab[MAX_LISTE]; int cpt; }; #endif Version 1 (de base) Attention!

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 taille() +1) return; pos--; for (i = (cpt - 1); i >= pos; i--) { tab[i+1] = tab[i]; } tab[pos] = x; cpt++; }

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; }

#ifndef _LISTEC__H #define _LISTEC__H #include using namespace std; // 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); //surcharge de << private: static const int MAX_LISTE = 5; int tab[MAX_LISTE]; int cpt; }; #endif Définition de la classe Liste en C++ (version 2) Constructeur de copie Surcharge op. = Surcharge op. << version 2

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 Constructeur de copie Définition de la classe Liste en C++ (version 2)

Surcharge de l’opérateur = Définition de la classe Liste en C++ (version 2) l1 = l2 // équivalent à l1.operator = (l2); operator ( ) {...} Syntaxe Liste& operator = (const Liste& l) {..} Exemple Utilisation

Surcharge de l’opérateur = Définition de la classe Liste en C++ (version 2) Liste l1;... 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 l1.tab l2.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) Si tab est un tableau dynamique

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

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; } 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   Surcharge de <<

Liste& operator = (const Liste& l){ cpt = l.cpt; for (int i=0; i<cpt;i+=1) tab[i]=l.tab[i]; return (*this); //retourner : une référence sur // l’objet courant } 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. = // Rappel: l1.operator = (l2);

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

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

void Liste::ajouter (int x, int pos) throw(int) { if (cpt==MAX_LISTE) throw 1; if (pos this->taille() +1) throw 2 ; //… } 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; }.... return 0; }

Définition de la classe Liste en C++ (version 3.2) #include using namespace std; #include #pragma warning( disable : 4290 ) // 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: static const int MAX_LISTE = 5; int tab[MAX_LISTE]; int cpt; }; Gestion des exceptions Usage d’une classe de la librairie stdexcept version 3.2

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 this->taille() +1) throw out_of_range("Ajouter:Position d'ajout erronée"); //… } 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; }.... return 0; }

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. 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. Gestion des exceptions #include suite..

Exceptions standard du langage std::exception std::logic_errorstd::runtime_error std::domain_error std::invalid_argument std::length_error std::out_of_range std::overflow_error std::underflow_error std::range_error std::bad_alloc

Définition de la classe Liste en C++ (version 4) #include using namespace std; #pragma warning( disable : 4290 ) template 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; T tab[MAX_LISTE]; int cpt; }; #include "Liste.inl" Liste générique version 4

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

Définition de la classe Liste en C++ (version 4) template 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

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

Utilisation de la classe Liste générique int main() { Liste l; // ou Liste 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

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

Deuxième partie Retour au type abstrait liste ordonnée, implantation par:  des tableaux dynamiques  des listes simplement chaînées  des listes doublement chaînées  des listes circulaires (anneaux)

Un tableau alloué du monceau (tas ou heap) Taille décidé par l’utilisateur #include using namespace std; #pragma warning( disable : 4290 ) template class Liste { public: //… private: int tailleMax; // taille maximum de la liste int cpt; // cardinalité de la liste T * tab; // tableau "dynamique" contenant les éléments de la liste } ; #include "Liste.inl" Liste ordonnée   Implantation dans un tableau dynamique

Gestion du tableau dynamique  Il faut donc modifier le constructeur d’une liste: allouer un tableau sur le tas et dont le pointeur sera assigné à au membre privé tab. template Liste ::Liste (int max) throw(bad_alloc) { tailleMax=max; cpt = 0; tab = new T [tailleMax]; }  Le destructeur de la liste : Libération de l’espace du tableau pointé par tab template Liste ::~Liste () // Destructeur { delete [] tab ; cpt = tailleMax = 0; }   Constructeur   Destructeur

Gestion du tableau dynamique  Il ne faut pas oublier le constructeur de copie: allouer un tableau sur le tas et dont le pointeur sera assigné à au membre privé tab puis copier de l’instance source template Liste :: Liste(const Liste & source) throw (bad_alloc) : tailleMax(source.tailleMax) { cpt= source.cpt; tab = new T [tailleMax]; for (int position =0; position < source.cpt; ++position) tab[position]= source.tab[position]; }   Constructeur de copie

Gestion du tableau dynamique  et la surcharge de l’opérateur = allouer un tableau sur le tas et dont le pointeur sera assigné à au membre privé tab puis copier de l’instance source, ne pas oublier de nettoyer… template Liste & Liste ::operator = (const Liste & l) throw(bad_alloc) { if (tab!=0) delete [] tab; //nettoyer... tab=new T [l.tailleMax]; for (int i=0; i< l.cpt; i++) tab[i]=l.tab[i]; tailleMax=l.tailleMax; cpt=l.cpt; return (*this); }   Surcharge de l’opérateur =

Les listes ordonnées Chaque élément appelé noeud contient deux parties : 1. une partie contenant l’information proprement dite 2. et une partie appelée pointeur qui lie le noeud au noeud suivant.  Le noeud étant un objet distinct, il est intéressant de définir une classe pour les nœuds (classe Noeud).  La classe Noeud contient un constructeur qui prend une valeur initiale pour la partie information. Elle contient également un destructeur qui ne fait rien de spécial.  Il est facile de voir les opération d’insertion et de suppression se font en un temps constant (O(1)) puisqu’elles consistent essentiellement en des mises à jour de pointeurs. Implantation dans une liste chaînée

Les listes ordonnées Implantation dans une liste chaînée // fichier Noeud.h // déclaration de la classe Noeud #ifndef NOEUD_H #define NOEUD_H class Noeud; typedef Noeud * elem; template class Noeud{ //Un noeud typique de la liste public: T el;//L'élément de base de la liste elem suivant;//Un pointeur vers le noeud suivant Noeud (const T& data_item, elem next_ptr = 0) : el(data_item), suivant(next_ptr) {} ~Nœud(){}; }; #endif el suivant

Les listes ordonnées Implantation dans une liste chaînée #ifndef LISTE_H #define LISTE_H #include "Noeud.h" #pragma warning( disable : 4290 ) template class Liste { public: Liste(){debut = 0;} // constructeur ~Liste(); // destructeur void ajouter(T x, int pos) throw(); int taille() const; bool appartient(T x,) const; friend ostream& operator << (ostream&, const Liste& ); private: elem debut; // Pointeur vers le dernier noeud de la liste } ; #endif

Implantation dans une liste chaînée Une meilleure version: utilisation d’une classe interne //… template class Liste { public: //Constructeurs Liste(){debut = 0;}// constructeur Liste(const Liste&) throw(bad_alloc);// constructeur de copie ~Liste();// destructeur //Surcharge d'opérateurs Liste & operator = (const Liste &) throw (bad_alloc); private: class Noeud{//Un noeud typique de la liste public: T el;//L'élément de base de la liste Noeud * suivant; //Un pointeur vers le noeud suivant Noeud (const T& data_item, Noeud * next_ptr = 0) : el(data_item), suivant(next_ptr) {} }; typedef Noeud * elem; elem debut; //Pointeur vers le premier noeud de la liste } ;

Implantation dans une liste chaînée template Liste :: ~Liste() {elem courant = debut; while(courant!=0) { debut=debut->suivant; delete courant; courant=debut; } ~Liste() // destructeur   Destructeur

Implantation dans une liste chaînée template int Liste :: taille() const { elem ptr; //Pour parcourir la liste int compte(0); //Pour compter les pointeurs non nuls ptr = debut; while (ptr != 0) { compte++; ptr = ptr->suivant; } return compte; } taille() // taille de la liste

Implantation dans une liste chaînée template bool Liste :: appartient(T& x) const { elem courant = debut; while (courant!=0) { if (courant->el == x) return true; courant = courant->suivant; } return false; } appartient() // recherche

Implantation dans une liste chaînée template void Liste :: ajouter(T x, int pos) throw(range_error, bad_alloc) { elem courant;//pointeur de service pour se promener dans la liste elem nouveau;//pour l'adresse de la nouvelle structure pour entreposer x int cpt=1;//compteur de boucle //Vérification des hypothèses (préconditions) //La position if(pos taille() +1) throw range_error("Position d'ajout erronée"); //La mémoire nouveau = new Noeud(x); //on appelle le constructeur de la classe Noeud nouveau->suivant = 0; //suite prochaine diapositive ajouter() // l’ajout d’élément

Implantation dans une liste chaînée //Cas où l'ajout se fait en première position if(pos==1) { nouveau->suivant=debut; debut = nouveau; return ; } //Ajout dans une autre quelconque position courant = debut;//on se positionne au début de la liste chaînée while (cpt< pos - 1) { courant=courant->suivant;//on passe à la structure suivante.. cpt++;//...et on compte } //A: courant pointe la structure d'avant le nouvel ajout nouveau->suivant = courant->suivant; //on chaîne la nouvelle structure … courant->suivant = nouveau;//on chaîne la structure qui doit précéder … } ajouter() // l’ajout d’élément

Implantation dans une liste chaînée template void Liste :: enleverEl(T x) throw(logic_error) { elem trouve = debut; elem pred; //on prend pour acquis que l'opérateur != s'applique sur x, le mieux est … while (trouve != 0 && trouve->el != x ) { pred = trouve; // pour marquer le noeud prédécesseur à celui qui contient x trouve = trouve->suivant; } if (trouve== 0) throw logic_error("EnleverEl: x n'est pas dans la liste"); else { //suite prochaine diapositive enleverEl() // enlever la première occurrence d’un élément

Implantation dans une liste chaînée else { if (debut == trouve) { / x est au début de la liste debut = debut->suivant; } else { //..il est ailleur pred->suivant = trouve->suivant; } // on "coupe" la structure supprimée de la liste trouve->suivant = 0; //libération de la mémoire associée à la structure supprimée delete trouve; } enleverEl() // enlever la première occurrence d’un élément

Implantation dans une liste chaînée template Liste & Liste ::operator = (const Liste & source)throw(bad_alloc) { //nettoyage... if (debut!=0) {elem temp= debut; while (debut !=0) { debut = temp->suivant; delete temp; temp = debut; } //suite prochaine diapositive Operator = () // surcharge de l’op. d’affectation

Implantation dans une liste chaînée if (source.debut== 0) debut = 0; // la liste originale est vide else { //la copie try{ //copie le permier noeud debut = new Noeud(source.debut->el); debut->suivant = 0; // copie le reste de la liste elem nouveau = debut; for(elem temp = source.debut->suivant; temp != 0;temp = temp->suivant) { nouveau->suivant = new Noeud(temp->el); nouveau = nouveau->suivant; nouveau->suivant = 0; } nouveau->suivant = 0; }catch(exception&){ //suite dans la prochaine diapositive Operator = () // surcharge de l’op. d’affectation

Implantation dans une liste chaînée catch(exception&){ //suite dans la prochaine diapositive //Si on arrive ici c'est qu'il y a une erreur d'allocation //On doit donc libérer la mémoire déjà allouée elem temp= debut; while (temp!=0) { debut = temp->suivant; delete temp; temp = debut; } //On relance alors l'exception pour indiquer qu'une erreur est survenue throw; } return (*this); } Operator = () // surcharge de l’op. d’affectation

Implantation dans une liste chaînée template class Liste { public: //.. friend ostream& operator << (ostream& f, const Liste& l){ elem courant=l.debut; while(courant!=0) { f el << " "; courant=courant->suivant; } return f; } private: //.. } ; Operator << () // surcharge de l’op. <<

Dans les situations où il est souvent nécessaire d’atteindre des éléments d'une chaîne qui se trouvent quelques positions avant un élément donné, on peut alors adjoindre, à chaque élément, un pointeur supplémentaire vers son prédécesseur. SommetGSommetD … Implantation dans une liste doublement chaînée Nœud typique d’une liste chaînée : Nœud typique d’une liste doublement chaînée : Info LienPtrG Info PtrD

Implantation dans une liste doublement chaînée template class Liste { public: //.. private: class Noeud{//Un noeud typique de la liste public: T el;//L'élément de base de la liste Noeud * suivant;//Un pointeur vers le noeud suivant Noeud * precedent;//Un pointeur vers le noeud précédent Noeud (const T& data_item, Noeud * next_ptr = 0, Noeud * pred_ptr =0) : el(data_item), suivant(next_ptr), precedent(pred_ptr){} }; typedef Noeud * elem; elem sommetG;//Pointeur vers le sommet à gauche elem sommetD;//...vers le sommet droit int cpt;//cardinalité de la liste } ;

Liste doublement chaînée Exemple d’une gestion des 2 pointeurs de chaînage SG = new …SG= sommetG SG  precedent = 0SD= sommetD SG  item = info SD = SG et Demander info Tant que info  sentinelle debut SD  suivant = new … SD  suivant  precedent = SD SD = SD  suivant SD  item = info Demander info fin SD  suivant = 0

Liste doublement chaînée Ajouter un élément Ajouter N avant P : …… P N

Ajouter un élément Ajouter N avant P : P  precedent  suivant = N N  precedent = P  precedent N  suivant = P P  precedent = N …… P N Liste doublement chaînée

Ajouter un élément Ajouter N avant P : P  precedent  suivant = N N  precedent = P  precedent N  suivant = P P  precedent = N … … P N Liste doublement chaînée

Ajouter un élément Ajouter N avant P : P  precedent  suivant = N N  precedent = P  precedent N  suivant = P P  precedent = N …… P N Liste doublement chaînée

Ajouter un élément Ajouter N avant P : P  precedent  suivant = N N  precedent = P  precedent N  suivant = P P  precedent = N …… P N Liste doublement chaînée

Ajouter un élément Ajouter N avant P : P  precedent  suivant = N N  precedent = P  precedent N  suivant = P P  precedent = N …… P N Liste doublement chaînée

Ajouter un élément Ajouter N avant P : P  precedent  suivant = N N  precedent = P  precedent N  suivant = P P  precedent = N …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après P : …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après P : N  suivant = P  suivant P  suivant  precedent = N P  suivant = N N  precedent = P …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après P : N  suivant = P  suivant P  suivant  precedent = N P  suivant = N N  precedent = P …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après P : N  suivant = P  suivant P  suivant  precedent = N P  suivant = N N  precedent = P …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après P : N  suivant = P  suivant P  suivant  precedent = N P  suivant = N N  precedent = P …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après P : N  suivant = P  suivant P  suivant  precedent = N P  suivant = N N  precedent = P …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après P : N  suivant = P  suivant P  suivant  precedent = N P  suivant = N N  precedent = P …… P N Liste doublement chaînée

Ajouter un élément Ajouter N après le sommet droit : … P N … Liste doublement chaînée

Ajouter un élément Ajouter N après le sommet droit : sommetD  suivant = N N  precedent = sommetD sommetD = N N  suivant = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N après le sommet droit : sommetD  suivant = N N  precedent = sommetD sommetD = N N  suivant = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N après le sommet droit : sommetD  suivant = N N  precedent = sommetD sommetD = N N  suivant = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N après le sommet droit : sommetD  suivant = N N  precedent = sommetD sommetD = N N  suivant = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N après le sommet droit : sommetD  suivant = N N  precedent = sommetD sommetD = N N  suivant = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N après le sommet droit : sommetD  suivant = N N  precedent = sommetD sommetD = N N  suivant = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N avant le sommet gauche : … P N … Liste doublement chaînée

Ajouter un élément Ajouter N avant le sommet gauche : N  suivant = sommetG sommetG  precedent = N sommetG = N N  precedent = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N avant le sommet gauche : N  suivant = sommetG sommetG  precedent = N sommetG = N N  precedent = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N avant le sommet gauche : N  suivant = sommetG sommetG  precedent = N sommetG = N N  precedent = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N avant le sommet gauche : N  suivant = sommetG sommetG  precedent = N sommetG = N N  precedent = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N avant le sommet gauche : N  suivant = sommetG sommetG  precedent = N sommetG = N N  precedent = 0 … P N … Liste doublement chaînée

Ajouter un élément Ajouter N avant le sommet gauche : N  suivant = sommetG sommetG  precedent = N sommetG = N N  precedent = 0 … P N … Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P …… P Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… P N Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… P N Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… P N Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… P N Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… P N Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… P N Liste doublement chaînée

Supprimer un élément Supprimer le nœud après P …… P Liste doublement chaînée

Supprimer un élément Supprimer le nœud après P N = P  suivant P  suivant = P  suivant  suivant P  suivant  precedent = P N  suivant =0 N  precedent = 0 delete N N = 0 …… P N Liste doublement chaînée

Supprimer un élément Supprimer le nœud après P N = P  suivant P  suivant = P  suivant  suivant P  suivant  precedent = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… N P Liste doublement chaînée

Supprimer un élément Supprimer le nœud après P N = P  suivant P  suivant = P  suivant  suivant P  suivant  precedent = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… N P Liste doublement chaînée

Supprimer un élément Supprimer le nœud après P N = P  suivant P  suivant = P  suivant  suivant P  suivant  precedent = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… N P Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… N P Liste doublement chaînée

Supprimer un élément Supprimer le nœud avant P N = P  precedent P  precedent = P  precedent  precedent P  precedent  suivant = P N  suivant = 0 N  precedent = 0 delete N N = 0 …… N P Liste doublement chaînée

Supprimer un élément Supprimer le nœud P …… P Liste doublement chaînée

Supprimer un élément Supprimer le nœud P P  precedent  suivant = P  suivant P  suivant  precedent = P  precedent P  precedent = 0 P  suivant = 0 delete P …… P Liste doublement chaînée

Supprimer un élément Supprimer le nœud P P  precedent  suivant = P  suivant P  suivant  precedent = P  precedent P  precedent = 0 P  suivant = 0 delete P …… P Liste doublement chaînée

Supprimer un élément Supprimer le nœud P P  precedent  suivant = P  suivant P  suivant  precedent = P  precedent P  precedent = 0 P  suivant = 0 delete P …… P Liste doublement chaînée

Supprimer un élément Supprimer le nœud P P  precedent  suivant = P  suivant P  suivant  precedent = P  precedent P  precedent = 0 P  suivant = 0 delete P …… P Liste doublement chaînée

Supprimer un élément Supprimer le nœud P P  precedent  suivant = P  suivant P  suivant  precedent = P  precedent P  precedent = 0 P  suivant = 0 delete P …… P Liste doublement chaînée

Supprimer un élément Supprimer le sommet gauche … N … Liste doublement chaînée

Supprimer un élément Supprimer le sommet gauche N = sommetG sommetG = sommetG  suivant sommetG  precedent = 0 N  suivant = 0 delete N N = 0 … N … Liste doublement chaînée

Supprimer un élément Supprimer le sommet gauche N = sommetG sommetG = sommetG  suivant sommetG  precedent = 0 N  suivant = 0 delete N N = 0 … N … Liste doublement chaînée

Supprimer un élément Supprimer le sommet gauche N = sommetG sommetG = sommetG  suivant sommetG  precedent = 0 N  suivant = 0 delete N N = 0 … N … Liste doublement chaînée

Supprimer un élément Supprimer le sommet gauche N = sommetG sommetG = sommetG  suivant sommetG  precedent = 0 N  suivant = 0 delete N N = 0 … N … Liste doublement chaînée

Supprimer un élément Supprimer le sommet gauche N = sommetG sommetG = sommetG  suivant sommetG  precedent = 0 N  suivant = 0 delete N N = 0 … N … Liste doublement chaînée

Supprimer un élément Supprimer le sommet gauche N = sommetG sommetG = sommetG  suivant sommetG  precedent = 0 N  suivant = 0 delete N N = 0 … N … Liste doublement chaînée

Supprimer un élément Supprimer le sommet droit Le même algorithme que pour supprimer le sommet gauche, mais en échangeant les rôles des pointeurs precedent et suivant et en remplaçant sommetG par sommetD. Liste doublement chaînée

Les listes chaînées circulaires permettent de rendre l’écriture de certains algorithmes d’une manière plus efficace. sommet... Implantation dans une liste circulaire (anneau) Cependant, il est plus intéressant d’avoir un pointeur dernier au lieu d’un pointeur sommet dernier...

Listes circulaires (les anneaux) template class Liste { public: //... friend ostream& operator << (ostream& f, const Liste& l){ if(l.dernier == 0) return f; elem courant = l.dernier->suivant; while(courant!=l.dernier){ f el suivant; } f el; return f; } private: class Noeud{ public: T el; Noeud * suivant; Noeud (const T& data_item, Noeud * next_ptr = 0) : el(data_item), suivant(next_ptr) {} }; typedef Noeud * elem; elem dernier;/*Pointeur vers le dernier noeud de la liste*/ } ;

Anneau bidirectionnel Sommet … Listes circulaires (les anneaux )

Les tableaux sont un type de données très utile en programmation mais présentent 2 limitations : 1.Les données sont contiguës (les unes derrières les autres) et donc l’insertion ou suppression d’un nouvel élément au milieu du tableau demande la recopie (le décalage) de tous les éléments suivants. =) insertion et suppression en O(n) 2. Augmenter la taille (par exemple si elle n’est pas connue a priori) nécessite la création d’un nouveau tableau =) O(n) 3. Les éléments doivent être placés de façon contigüe (dans un seul gros bloc) en mémoire, ce qui fait qu’on ne peut pas « remplir les trous » en mémoire. Comparaison des implantations de la liste

Liste avec tableau: 1. Insertion et suppression sont O(n). 2. Précédent et accès direct sont O(1). 3. Tout l’espace est alloué à l’avance. 4. Pas d’espace autre que les valeurs. Liste dans une liste chaînée: 1. Insertion et suppression sont O(1). 2. Précédent et accès direct sont O(n). 3. L’espace augmente avec la liste. 4. Chaque élément requiert de l’espace pour les pointeurs Comparaison des implantations de la liste

Laboratoire #3  Nous vous fournissons 3 packetages, un par projet/implantation que vous devez faire: tableau dynamiquetableau dynamique liste doublement chaînéeliste doublement chaînée liste circulaireliste circulaire Implantation d’une liste ordonnée Dans chacun d'eux, vous devez compléter le fichier.inl étant donné le modèle d'implantation décrit dans la partie privée de la classe Liste. Bien entendu, les 3 implantations demandées doivent être génériques. Ces 2 main()Ces 2 main() fournis sont pour tester les 3 packetages (séparément), un main() pour instancier une liste ordonnée d'entiers et un autre pour déclarer une liste d'objets définis dans la classe ClasseTests.h que nousClasseTests.h vous fournissons également.

Éléments du C++ à voir dans la semaine Rappel (semaine 1)  Du C au C++  Les entrées/sorties (important pour cette semaine)  L'espace de nommage  Les types vector et string  Concepts orientés objet  Classe et objet Éléments du C++ à voir dans la semaine Rappel (semaine 1)  Du C au C++  Les entrées/sorties (important pour cette semaine)  L'espace de nommage  Les types vector et string Rappel (semaine 2)  Concepts orientés objet  Classe et objet Cette semaine  Programmation générique (template)  La gestion des exceptions

Éléments du C++ à maîtriser  les éléments syntaxiques nouveaux par rapport au langage C  notion de classe, constructeurs, destructeur  constructeur de copie et surcharge de l'op. = (minimum exigé dans une classe)  les attributs et méthodes d'une classe: friend, static, const  la généricité (template)

Le point sur les normes de programmation Normes de programmation: Commentaires d’interface Commentaires d’implémentation Découpage logique d’un programme La gestion des exceptions Style de programmation Voir sur le site Web du cours, section Documentations/Normes de programmation: NormesProgrammation.pdf Resume.h (à propos des commentaires Doxygen)

L'interface... /** * \brief * * \pre * * \post * * \exception */ Résumé des balises de Doxygen Implémentation... /** * \fn * * \param[in] * \param[out] * * \return Section Documentations/Normes de programmation: Resume.h (à propos des commentaires Doxygen)

template class Liste{ public://L'interface... /** * \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 */ void ajouter(T x, int pos) throw(range_error, length_error);... private:...//Modèle d'implantation }; Fichier Liste.h Spécifications « C++ » (version Doxygen)

/** * \fn void Liste :: ajouter (T x, int pos) * * \param[in] x Élément à ajouter * \param[in] pos Position où insérer l'élément * */ template void Liste ::ajouter (T x, int pos) throw(out_of_range, length_error) { Commentaires d’implémentation (version Doxygen)

Avantages des TDA Écriture de programmes en couches : la couche supérieure traite le problème dans les termes du domaine de problèmes Empiler (x, P) la couche inférieure entre dans les détails du langage de programmation tab[sp++] = x Séparation claire des offres de service du codage Et.. facilité de compréhension et d'utilisation des modules de codes prise en compte de types complexes briques d'une structuration modulaire rigoureuse introduction à la programmation objet Théorie du contrat

Non-respect de la théorie du contrat On modifie sauvagement les données dans structures à tous les endroits où on a besoin des structures. On considère que tous les membres de la structure sont accessibles. Ça semble plus facile à faire pour un débutant. Un changement de conception d’une structure devient impossible dès que le logiciel prend de l’envergure. Respect de la théorie du contrat L’idée est de préparer le logiciel à un changement radical du contenu de la structure. On passe obligatoirement par des fonctions pour accéder aux membres structures. On ne fait jamais de supposition sur l’existence de tel membre. Plus difficile à réaliser pour un débutant. Ça facilite les changements de conception de structures. Avantages des TDA

struct Boite { int taille; int direction; } ; /*définition d’un modèle interne pour un type Boite*/ /*Les opérateurs du type Boite*/ int getTailleBoite(Boite b);/* Retourne la taille de b*/ Boite setTailleBoite(Boite b, int nouvelleTaille); /*Assigne une nouvelle taille à b*/ Boite augmenterTailleBoite(Boite b, int i); /*Augmente la taille de b d’une valeur égale à i */ Ce programme brise l’encapsulation, à la ligne 4: il y a non respect de la théorie du contrat. int main() { Boite b; // ligne 1 int t; // ligne 2... // ligne 3 t = b.taille; // ligne 4 t = t+5;// ligne 5 b=setTailleBoite(b,t); // ligne 6... } Exemple

Inconvénients des TDA  L'utilisateur d'un TDA connaît les services mais ne connaît pas leur coût.  Le concepteur du TDA connaît le coût des services mais ne connaît pas leurs conditions d'utilisation.  Le choix des primitives est quelque fois difficile à faire.

Retour sur le calcul d’adresses char *tab[ ] = { "Eleves","Prof","Stage"};  tab : est équivalent à : &tab[0] : c'est l'adresse du premier élément du tableau.  *tab : est équivalent à : tab[0] : c'est le premier élément du tableau, c'est à dire l'adresse du premier caractère de la chaîne "Eleves".  tab[1] : est l'adresse sur le premier caractère de la chaîne "Prof".  *(tab+1) : est équivalent à : tab[1]

Retour sur le calcul d’adresses char *tab[ ] = { "Eleves","Prof","Stage"};  *tab[1] : est le caractère pointé par tab[1] : c'est le caractère 'P' de la chaîne "Prof".  **tab : est équivalent à : *tab[0] :c'est le caractère 'E' de la chaîne"Eleves".  **(tab+1) : est équivalent à : *tab[1] :c'est le caractère 'P' de la chaîne"Prof".  *(tab[2]+1) : est équivalent à : tab[2][1] :c'est le caractère 't' de la chaîne"Stages".

Pointeur sur une fonction int tab[10];  tab est l'adresse du premier octet du tableau. void fonctionQc(int i, int j){…}  À l’instar du nom d’un tableau, fonctionQc est l'adresse du premier octet implantant la fonction. Comme le nom d’une fonction est une adresse, il est alors possible de déclarer une variable de type pointeur sur la fonction :  void (*f)(int, int); À la déclaration, il faut définir :  le type des paramètres  le type de retour

Exemple int addition(int i, int j); int main() { int (*fonction)(int, int); //déclaration d'un pointeur sur une fonction int i=1, j=2, k; //déclaration de 3 entiers fonction = &addition; // ou bien fonction = addition k = fonction(i,j); k = (*fonction)(i,j); k = addition(i,j); k = (*addition)(i,j); return(0); }

Un pointeur sur une fonction comme paramètre d'une fonction void tri(int *tab, int size, bool (*compare)(int, int)) { void swap(int *, int *); for (int idx = 1; idx <= size - 1; idx++) for (int count = 0; count <= size - 2; count++) if ((*compare)(tab[count], tab[count + 1])) swap(&tab[count], &tab[count + 1]); } L'ordre du tri est défini par la fonction compare Exemple