Structures de données IFT-2000 Abder Alikacem Introduction au cours Semaine 1 Édition Septembre 2009 Département d’informatique et de génie logiciel
Plan Introduction Analyse et abstraction Modélisation Types de données abstraits Spécifications Implantation Plan et modalités du cours
Viny, la mascotte du cours!!
Conventions de représentation Conventions de représentation de l’information(Interface): integer idem pour tout programme sur un même ordinateur, utilisant le même langage: int x; Conventions d’utilisation (Opérateurs): integer pas de décimales: x = 5/2; D’une manière générale, pour définir un type de données, on a besoin de décrire éventuellement: son nom (syntaxe); sa sémantique; son domaine de valeurs; ses contraintes; etc.. + son comportement: { opérateurs } Interface publique
Conventions de représentation Structuration de base = types simples (ex. le type int) convention de représentation interne (Modèle interne): int x, y; choix de représentation interne {implantation de l’interface} Modèles internes ± bit de signe complément à 1: C1 complément à 2: C2
Conventions transparentes Transparence des types de base: int x; y = x++; 1 00011101010101 00010101010101 00101010100001 11111100000101 ….
Besoin de types plus complexes! Caractéristiques d’un système sont souvent difficiles à être représentées directement dans un ordinateur. Existences de distances conceptuelles. Comment réduire ces distances? Analyse (décomposition descendante) du domaine Abstraction (à partir des objets informatique de base jusqu’à une possible représentation du réel) Encapsulation Masquage d’information Cacher les secrets d’une implémentation. C’est la modélisation!
Construction d’un modèle Modélisation: Réalité Modèle
Construction d’un modèle Modélisation: Réalité Modèle
Construction d’un modèle Modélisation: Réalité Modèle
Construction d’un modèle Modélisation: Réalité Modèle x
Construction d’un modèle Modélisation: Réalité Modèle x float x;
Construction d’un modèle Modélisation: Réalité Modèle x struct Pt { float x; float y; float z; } ; float x;
Construction d’un modèle Modélisation: Réalité Modèle x struct Pt { float x; float y; float z; } ; struct Plan { pt p[4]; } ; float x;
Construction d’un modèle Modélisation: Réalité Modèle x struct Pt { float x; float y; float z; } Pt; struct Boite { Plan pl[6]; }; struct Plan { Pt p[4]; }; float x;
Construction d’un modèle Modélisation: Réalité Modèle x struct Pt { float x; float y; float z; }; struct Boite { Plan pl[6]; }; struct Plan { Pt p[4]; }; Boite b1; float x;
Modélisation = transfert Réalité Modèle Boite b1; … b1.rotation(b1,45);
Création d’un modèle Modélisation: modèle près de la réalité modèle distant des détails d’implantation Boite b1; … b1.rotation(b1,45); struct boite { Plan pl[6]; }; struct Plan { Pt p[4]; }; struct Pt { float x; float y; float z; }; float x;
Les types de données abstraites (TDA) Modélisation: modèle près de la réalité modèle distant des détails d’implantation boîte noire Boite b1; … b1.rotation(b1,45); typedef struct { plan pl[6]; } boite; typedef struct { pt p[4]; } plan; typedef struct { float x; float y; float z; } pt; float x;
Les types de données abstraites (TDA) Programme indépendant de l’implantation du type Boite: Boite b1, b2, b3; b1.creer(…); b2 = b1; b3 = b2; b1.rotation(45); b2.poseSur(b3); Boite est alors un type abstrait!
Les types de données abstraites (TDA) Un type de données abstrait modélise l’« ensemble des services » désirés plutôt que l’organisation intime des données (détails d’implémentation). Il est créée à partir d’un ensemble de données organisé et reliées logiquement. Il est caractérisée par : son contenu les interactions possibles (manipulation, accès, ...) est défini uniquement par ses conventions d’utilisation par le comportement des objets de ce type (i.e., par les méthodes applicables sur les objets de ce type) ne décrit pas le modèle d’implantation choisi sert à isoler les programmes des données (structuration interne) crée une indépendance des applications face aux modèles d’implantation (continuité de la programmation structurée) permet l’encapsulation de la définition d’un type
Les types de données abstraites (TDA) Indépendance programmes/données: modularité de développement facilité d’assemblage de modules validation modulaire et continue Réutilisation Évolution coût d’entretien
Incarnation d’un TDA L’interface (fichier .h) Une incarnation (une réalisation, une mise en œuvre, une « implémentation ») d'un TDA est la déclaration des structures de données particulières et la définition des opérations primitives retenues pour représenter le TDA. L’interface (fichier .h) Et la définition (i.e le code) des opérations primitives dans un langage particulier L’implémentation (fichier .cpp) les programmeurs ont deux casquettes: le concepteur du TDA qui met en œuvre les primitives et doit connaître la représentation interne adoptée. On parle de programmation de bas niveau. l'utilisateur du TDA qui ne connaît que les services (les opérations) et n'accèdent jamais à la représentation interne. On parle de programmation de haut niveau.
L’interface main() Avec les types de données de base: programme int x, y; y = x + 1; interface int x, y; =, +, -, ++, --, *, /, ...
L’interface main() Avec des types structurés: interface programme données boite b1; rotation(b1,45); interface Boite b1; rotation, poseSur, ...
Exemple d’une interface d’un type abstrait //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.. Interface en C++ // Fichier Liste.h #include <iostream> #ifndef _LISTEC__H #define _LISTEC__H class Liste { public: Liste(); //constructeur ~Liste(); //destructeur void ajouter (int x, int pos) throw(range_error, length_error); int taille() const ; bool estVide() const; //etc… private: static const int MAX_LISTE = 100; int tab[MAX_LISTE]; int cpt; }; #endif C’est la partie publique Interface en C
Modèle d’implantation Exemple En C En C++ // Fichier Liste.h #include <iostream> using namespace std; #ifndef _LISTEC__H #define _LISTEC__H class Liste { public: … //l’interface publique private: static const int MAX_LISTE = 100; int tab[MAX_LISTE]; int cpt; }; #endif //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 C’est la partie privée
Exemple d’une implémentation en C /******************************************************************** Fichier Liste.c Version 1.0 Janvier 2007 (c) IFT-10541 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èses: pos est compris entre 1 et la taille de la liste + 1 (|L| + 1) inclusivement, il y a assez de place pour ajouter x. */ …
Exemple d’une implémentation en C (suite) 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...
Exemple d’une implémentation en C++ /**Commentaire style Doxygen * \file Liste.cpp * \brief Le code des opérateurs de la liste. * \author Abder * \version 0.1 * \date septembre 2009 * * Implémentation de la classe générique Liste. */ #include "Liste.h"
Exemple d’une implémentation en C++ /** Commentaire style Doxygen * \fn void Liste:: ajouter (int x, int pos) * * \param[in] x Élément à ajouter * \param[in] pos Position où insérer l'élément */ Un main de test: Fichier Main.cpp #include "Liste.h" 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(); …; } .... 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"); //etc… }
Spécifications d’une interface main() données programme int x, y; y = x + 1; Interface = ensemble d’opérations ou servies fournies sur un type abstrait (conventions et contraintes + comportement) { prototypes des opérateurs} + spécifications formelles
Spécifications « langage C » Exemple: ajout dans une liste ordonnée 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
Spécifications version dOxygen (dans une classe) // Le type Liste 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(int x, int pos) throw(range_error, length_error); private: ...//Modèle d'implantation }; Fichier Liste.h
Résumé des balises de Doxygen L'interface ... /** * \brief * * \pre * \post * \exception */ Implémentation ... /** * \fn * * \param[in] * \param[out] * \return Section Documentations/Normes de programmation: Resume.h (à propos des commentaires Doxygen)
Avantages des TDA Théorie du contrat É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
Avantages des TDA 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. 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 Exemple 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.
Tâches à maîtriser interface données programme 2.2 2.1 1 2 spécification formelle d’un type abstrait choix d’un modèle d’implantation Programmeur d’application Gestionnaire de données 2.2 2.1 1 Analyse: -besoins -contraintes 2 Conception: -choisir un modèle d ’implantation -réaliser l’implantation
Objectifs du cours Programmation des structures de données et des algorithmes qui les manipulent. Concepts : abstraction, généricité, encapsulation, programmation orienté objet Techniques : la manipulation des pointeurs, la gestion de la mémoire dynamique Structures de données Listes, Piles, Files, Arbres, Graphes, Tables de dispersion Tris Choix : Présentation sous forme de Types de Données Abstraits Analyse d’algorithmes (notation asymptotique) Écriture de programmes lisibles et efficaces (complexité)
Discussion sur le plan de cours Contenu du cours Prerequis Évaluations Apprentissage du langage C++ Compilateurs, OS Notes de cours et le manuel recommandé Site Web, liste de diffusion, forum, courriel Laboratoires, autres exercices SVN, dOxygen, Eclipse, VS 2008 Les équipes dans les TPs Charge de travail Conseils Méthode de travail Utilisation du site Web du cours
Le point sur les 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)