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

Université Blaise Pascal

Présentations similaires


Présentation au sujet: "Université Blaise Pascal"— Transcription de la présentation:

1 Université Blaise Pascal
Structures de données Olivier Raynaud Université Blaise Pascal

2 Le plan du cours Chapitre 1 : Niveaux de description
(Ordinateur, instruction, langage, donnée, variable…) Chapitre 2 : Concepts de valeur et de type (Valeur, type, type simple, type composé, typage …) Chapitre 3 : Types récursifs et schéma d’induction (Listes, graphe, arbre, tas …) Chapitre 4 : Types de Données Abstraits (T.D.A.) (Définition, pile, file, file de priorité, ensemble dynamique …) Chapitre 5 : Fonction de hachage (Hypothèse, hachage chaîné, adressage ouvert …)

3 Le plan du cours Chapitre 6 : Complexité
( Opération élémentaire, notation O…) Chapitre 7 : Représentation des graphes (Définition, listes d’adjacence, matrice…) Chapitre 8 : Applications algorithmiques (Gestion des expressions arithmétiques, codage de Huffman…)

4 Bibliographie L’intelligence et le calcul (J.P. Delahaye) Belin
[XUO92] Mathématique discrète et informatique (N.H. Xuong) Masson [CLR90] Introduction à l’algorithmique (T. Cormen, C. Leiserson, R. Rivest) Dunod [W90] Programming Language Concepts and Paradigme (David A. Watt) Prentice Hall [KR78] The C Programming Language (B.W. Kernighan and D.M. Ritchie) Prentice Hall

5 Bibliographie Turbo Pascal 4.0 Manuel d’utilisation Borland
[GJ00] Computers and intractability (M.R.Garey and D.S.Johnson) Freeman [HOF93] Godel Escher Bach (D.Hofstadter) InterEdition [Ca66] La logique symbolique (L.Caroll) [Tis]w3.mines.unancy.fr/~tisseran/cours/architectures/

6 Niveaux de description
Chapitre 1 On appelle niveau de description le degré de granularité choisi pour évoquer, décrire ou parler d’un concept. Lors d’un échange verbal le niveau de description choisi pour évoquer un concept dépend de certains paramètres comme le contexte de l’échange ou le niveau de compétence et de connaissance de l’interlocuteur. Le niveau choisi peut évoluer au cours de l’échange. C’est une caractéristique de l’intelligence que de pouvoir changer ce niveau facilement, intuitivement au cours de l’échange. Dans la suite de cette introduction nous donnons une description possible de ce qu’est un ordinateur. Niveaux de description Olivier Raynaud Université Blaise Pascal

7 Base conceptuelle d’un ordinateur
Chap. 1 : Niveaux de description Base conceptuelle d’un ordinateur On peut évoquer la présence de l’horloge qui permet de synchroniser l’ensemble des instructions. Extrait de [Tis]

8 Chap. 1 : Niveaux de description
La mémoire La mémoire est divisée en parties physiques appelées mots (par exemple mots pour une mémoire). Un mot se divise en bits (la taille d’un mot correspond à la taille d’un registre ou du bus) X O Il existe un lien naturel entre la taille d’un mot (d’une adresse) et la taille globale de la mémoire adressable. Les bits ne sont pas adressables un par un. Les adresses sont tout les 8 bits, ce principe est stable depuis 30 ans. Ex : 1980 processeur 16bits permet de coder des entiers de 0 à d’où une mémoire vive limitée à octet; Ex : 1990 processeur 32 bits permet de coder des entiers de 0 à 4.10^9 d’où une mémoire vive limitée à4 giga octets; Ex : 2000 processeur 64 bits … Contacts magnétiques : la convention habituelle est d’interpréter ses bits comme des « 0 » ou des « 1 ». Cela pourraient être des creux ou des bosses, des hauts et des bas. La convention a pour défaut de faire croire que les ordinateurs ne manipulent que des nombres codés en binaires. C’est faux il n’y a aucune raison de lire ses bits comme des nombres, il peut s’agir du codage de n’importe quoi d’autre : lettres, textes, images, pixels, instructions … Les bits sont des contacts magnétiques qui peuvent être dans l’une ou l’autre position.

9 Interprétation Mémoire : Les mots de la mémoire contiennent les
Chap. 1 : Niveaux de description Interprétation Mémoire : Les mots de la mémoire contiennent les données à traiter ou les instructions pour traiter ces données. La première partie du mot contient le nom du type de l’instruction à exécuter. La seconde partie contient l’adresse numérique d’un mot (ou des mots) sur lequel exécuter l’instruction.

10 Unité centrale et registre
Chap. 1 : Niveaux de description Unité centrale et registre L’unité centrale dispose d’un pointeur spécial (le registre appelé compteur ordinal ou IP) qui désigne le prochain mot à être interprété comme une instruction Exemple ADD AX, 1983 MOV AX, 1982 PUSH AX (ADD)Additionner le mot désigné dans l’instruction à un registre : le premier paramètre contient le nom d’un registre dans lequel effectuer l’addition de valeur donnée en second paramètre. (MOV)Stocker le mot désigné dans l’instruction sous forme de lettres : le premier paramètre contient le registre contenant la valeur à stocker à l’adresse correspondant au second paramètre. (JUMP)Sauter au mot désigné dans l’instruction : le seul paramètre est l’adresse de la prochaine instruction à exécuter. Ces instructions sont données en syntaxe Microsoft “MOV AX, 1982” place l’entier 1982 dans AX. “ADD AX, 1983” ajoute à AX le nombre 1983 et place le résultat dans AX. « PUSH AX » L’effet de cette instruction est d’empiler le mot contenu dans le registre AX. Autrement dit, SP est automatiquement décrémenté de 2, puis AX est copié à l’adresse SS:SP. Il y’a différents types d’instruction MOV ou ADD etc en fonction des opérandes (cst, regsitres et toutes les combinaisons des deux), donc en fait chaque fonction est codées par un entier. Il existe 16 registres AX, BX,CX,DX, BP, SP, SI, DI, CS, DS, ES, SS, IP,

11 Chap. 1 : Niveaux de description
Espace de stockage Un espace de stockage est une collection de cellules. Chaque cellule a un statut courant: alloué ou non alloué Chaque cellule allouée a un contenu courant qui est soit une valeur stockée soit une valeur indéfinie. Considérons la déclaration suivante en Pascal : var n : integer une cellule non-allouée devient allouée et son contenu est indéfini, n dénote cette cellule. n:=0 change à 0 le contenu de cette cellule dénotée par n, n+1 désigne le contenu de n auquel on ajoute 1, n :=n+1 ajoute 1 au contenu de la cellule. A la fin du block d ’instructions contenant la déclaration de la variable n, le statut de cette cellule devient non-alloué. ? 1 Nous pouvons voir chaque cellule allouée comme une boite contenant la valeur d’une variable primitive ou un indéfini « ? « .

12 Chap. 1 : Niveaux de description
Variable Définition : une variable est un objet qui contient une valeur, cette valeur sera inspectée ou mise à jour aussi souvent que désirée. Une variable de type composé est constituée de composants pouvant être inspectés de manière sélective. On peut citer des exemple d ’utilisation: les variables sont parfois utilisées pour modéliser le monde réel comme la date du jour, le temps courant et des résultats de l ’économie d ’un pays. Question : d ’autres variables sont connues pour être indépendantes des programmes, citez des exemples? Les fichiers externes, les base de données météo par exemple, dans ce cas de variables la mise à jour se fera de façon sélective. En Pascal une variable de type T est défini pour avoir la même structure qu’une valeur de type T.

13 Exemple : variable composée
Chap. 1 : Niveaux de description Exemple : variable composée type Mois = (jan, fev, mar,…,dec) Date = record m : Mois; j : end; var leJour : Date; … leJour.j := 23; leJour.m := fev leJour leJour.m leJour.j fev A noter : Ainsi une variable de type composé occupera plusieurs cellules. 23

14 La réunitarisation Extrait de [HOF93] Chap. 1 : Niveaux de description
L’idée de réunitarisation : un groupe d’élément est considéré comme une seule unité. La limite d’une unité ressemble un peu à la membrane d’une cellule ou à la frontière d’un état : elle confère une identité distincte à l’assemblage d’éléments quelle définit. Selon le contexte on peut vouloir ignorer la structure interne de l’unité ou au contraire la prendre en compte. Extrait de [HOF93]

15 Caractéristique d’un langage
Chap. 1 : Niveaux de description Caractéristique d’un langage Un langage doit être universel (tout problème doit avoir une solution qui peut être programmé dans le langage); Le langage doit être le plus naturel possible; Le langage doit être implémentable sur un ordinateur. La notion de concepts ou de paradigmes: Certains langages comme le Pascal ont été développé par une seule personne, d ’autres par des groupes plus large de personnes. L’expérience montre que plus le nombre de personnes est grand moins le langage est compact et cohérent. Un langage doit être universel : c ’est à dire que tout problème doit avoir une solution qui peut être programmé dans le langage. (bien sur il faut que ce problème admette une solution). On a montré que des langages permettant de définir des fonctions récursives étaient universels. Par contre des langages ne permettant ni récursion, ni itération ne pourront être universel. Le langage doit être le plus naturel possible. Le langage doit être implémentable sur un ordinateur : les notations mathématiques ne serait pas un bon langage, car certaines fonctions mathématiques sont incalculables par un ordinateur.)

16 Syntaxe et sémantique du langage
Chap. 1 : Niveaux de description Syntaxe et sémantique du langage La Syntaxe concerne la forme du programme, la façon dont les variables, les expressions et les instructions sont disposées ensemble pour former un programme. La Sémantique concerne le sens à donner à un programme, sont comportement lors de son exécution. Alors pourquoi parle-t-on de langage? Les langages naturels comme les langages de programmation disposent à la fois d’une syntaxe (la forme) et d’une sémantique (le sens). Mais les langues naturelles sont beaucoup plus riches, expressives et subtiles. La syntaxe influence la façon dont les programmes sont écrits par les programmeurs, lu par les autres programmeurs et décomposés par l’ordinateurs. La sémantique détermine comment le programme est composé par le programmeur, compris par les autres programmeurs et interprété par l ’ordinateur. La syntaxe est importante , mais la sémantique l’est encore plus. Dans ce cours nous nous intéressons à la sémantique. Nous étudierons les principaux concepts, nous verrons comment certains langages font la confusion entre des concepts distincts, admettent ou refusent certains concepts.

17 Chap. 1 : Niveaux de description
Le Langage machine Ce langage est l’unique langage compréhensible pour un processeur. Dans un langage machine, les types d’opérations possibles constituent un répertoire fini qui ne peut être étendu. Tous les programmes doivent être constitués de ces instructions. Ici nous pouvons faire deux remarques: a) A quoi ressemble un programme écrit en langage machine? Une séquence de 0 et de 1. Nous évoquons ici l’image de l’A.D.N. qui code nos cellules. b)Il existe encore un niveau inférieur au langage machine, c’est le câblage par fil qui assure le bon déroulement des opérations.

18 Le langage d’assemblage
Chap. 1 : Niveaux de description Le langage d’assemblage Le langage d’assemblage est situé au dessus du langage machine dans la hiérarchie des langages. Il existe une correspondance entre les instructions en langage d’assemblage et les instructions en langage machine. Exemple : L’idée du langage d’assemblage est de réunitariser chacune des instructions en langage machine de telle sorte qu’au lieu d’écrire la séquence de bits «   » pour avoir une instruction d’addition d’un nombre à un autre il suffise d’écrire « ADD » et d’indiquer le mot en mémoire par un nom plutôt que par une adresse en notation binaire. Contrairement à un langage de haut niveau, il y a une correspondance un à un entre le code assembleur et le langage machine, ainsi il est possible de traduire le code dans les deux sens sans perdre d'information. La transformation du code assembleur en langage machine est accomplie par un programme nommé assembleur, dans l'autre sens par un programme désassembleur. Un programme en langage d’assemblage est donc un programme en langage machine lisible par les humains. La partie de code (en syntaxe unix) signifie de mettre la valeur hexadécimale 61 (97 en décimal) dans la partie de registre 'AL'.) (AL correspond aux 8 premiers bits de AX). Le $ indique la constante, 0x sera suivi d’un nombre en exa, et le % provient de la syntaxe Unix). On aurait en syntaxe Microsoft l’instruction : MOV AL, 61h mov $0x61, %al

19 Chap. 1 : Niveaux de description
Un morceau d’A.D.N. tcgcgcgatctttgagctaattagagtaaattaatccaatctttgacccaaatctctgctggatcctctggtatttcatgttggatgacgtcaatttctaatatttcacccaaccgttgagcaccttgtgcgatcaattgttgatccagttttatgattgcaccgcagaaagtgtcatatctgagctgcctaaaccaaccgccccaaagcgtacttgggataaatcaggcttttgtgatctgttctaataatggctgcaagttatcaggtagatccccggcaccatgagtggatgtcacgattaaccacaggccattcagcgtaagttcgtccaactctgggccagaagttttctgtagaaaacccagcttcttctaatttatccgctaaatgttcagcaacatattcagc Il s’agit d’une suite de nucléotides . Imaginons maintenant une description atome par atome de cette séquence. Chaque nucléotide contient environ 25 atomes. Voilà se que serait un programme en langage machine. Ici il s’agit d’un morceau de la séquence de base du chromosome du bactériophage PhiX174. C’est le premier génome complet d’un organisme qui est été transcrit. Il faudrait environ 2000 pages de ce type pour montrer la séquence de base d’une seule cellule. On peut revenir à l’image de l’ADN, la différence est la même qu’entre la fastidieuse description atome par atome d’une chaîne ADN, et sa description à l’aide des abréviations de ses sous-unités (A,C,G,T). Nous aurions donc sous les yeux un programme en langage d’assemblage (les atomes constituant ces nucléotides étant les bits). Extrait de [HOF93]

20 Chap. 1 : Niveaux de description
L’assembleur Question : Que se passe-t-il si l’on fourni au matériel un programme en langage d’assemblage? Le programme « Assembleur» est un programme de traduction en langage machine. Une fois le programme « assemblé » (traduit) il peut être exécuté. Que se passe-t-il si l’on fourni au matériel un programme en langage d’assemblage? Que se passe-t-il si l’on transmet au noyau d’une cellule une séquence d’ADN écrite sur un morceau de papier plutôt qu’en substance chimique? Vous pouvez alors dire que l’un ou l’autre des programmes est exécuté. Il n’y aucune raison d’hésiter à décrire les choses d’un point de vue plus élevé.

21 Les langages de compilation
Chap. 1 : Niveaux de description Les langages de compilation Principalement deux réflexions ont mené au concepts de langages évolués (1950) : Il existe des modèles fondamentaux lorsque l’on essaie de formuler des algorithmes. Les programmes étaient toujours constitués d’unités de haut niveau indépendantes. Il existe des modèles fondamentaux lorsque l’on essaie de formuler des algorithmes: En général un élément d’algorithme de haut niveau se compose non pas d’une ou deux instructions en langage machine, mais d’un ensemble important d’instructions (les boucles par exemple) Les programmes étaient toujours constitués d’unité de haut niveau indépendantes, qu’il semblait nécessaire de pouvoir appelées par des noms. L’opération de réunitarisation serait ainsi directement intégrée au langage, le programme pourrait constituer ces propres modules, ayant chacun un nom et utilisable en chacun des points du programme. Les nouveaux langages fondés sur ces idées ont été baptisés langages de compilation

22 Les trois niveaux de description
Chap. 1 : Niveaux de description Les trois niveaux de description Niveau en langage machine: « Exécution du programme interrompue au point  » Niveau en langage d’assemblage: « Exécution du programme interrompue lorsque l’instruction DIV (division) a été rencontrée » Niveau en langage de compilation: « Exécution du programme interrompue lors de l’examen de l’expression algébrique «  (A+B)/Z». »

23 Chap. 1 : Niveaux de description
Les compilateurs Vers 1950, on a réussi à écrire des programmes appelés compilateurs, dont la fonction était de traduire des langages de compilation en langage machine. Question : Dans quel langage sont écrits ces compilateurs?

24 L’amorçage Langage de compilation Langage d’assemblage Compilateur
Chap. 1 : Niveaux de description L’amorçage Langage de compilation Langage d’assemblage Compilateur Les assembleurs et les compilateurs sont deux types de traducteurs en langage machine. De plus, étant donné qu’ils sont eux mêmes des programmes ils sont également au départ écrits dans un langage donné. Ce sont les lignes ondulées. Au fur et à mesure que la programmation a réalisé des progrès, on s’est aperçu qu’il était possible d’utiliser un compilateur partiellement écrit pour compiler des extensions de lui-même. Autrement dit dès qu’un noyau minimal d’un compilateur aurait été écrit, ce compilateur minimal pourrait traduire de plus gros compilateur en langage machine, lesquels pourraient à leur tour traduire des compilateurs plus gros encore, jusqu’à ce que le compilateur entièrement développé ai été compilé. Ce processus est métaphoriquement appelé l’amorçage. C’est un peu le même principe que l’acquisition du langage, l’enfant atteint un niveau d’élocution critique dans sa langue maternelle à partir duquel son vocabulaire s’élargit considérablement et sa faculté d’élocution progresse à pas de géant parce qu’il peut se servir du langage pour étendre son langage. Assembleur Langage machine Extrait de [HOF93]

25 Chap. 1 : Niveaux de description
Les interpréteurs Ils assurent la traduction des langages évolués en langage machine en lisant un programme ligne à ligne et en exécutant immédiatement cette ligne. Un interpréteur est donc au compilateur ce qu’un interprète simultané est à un traducteur. Le LISP (LIst PRrocessing) inventé par John McCarthy (1958) Ce type de langage (fonctionnels) a rencontré un grand succès auprès des chercheurs en intelligence artificielle (cf. machine Eliza). Un compilateur reçoit des données en entrée (un programme en Algol) et produit une sortie (une longue séquence d’instructions en langage machine). Un interpréteur n’est pas un compilateur ligne à ligne. Dans un interpréteur, les opérations de lecture d’une nouvelle ligne, de compréhension de celle-ci et d’exécution sont entremêlées et simultanées. Ainsi un programmeur peu créer son programme ligne à ligne et ainsi le tester au fur et à mesure.

26 Historique 1950 1960 1970 1980 Extrait de [W90] L. logiques
Chap. 1 : Niveaux de description Historique Extrait de [W90] 1950 Fortran Lisp 1960 Algol60 Cobol Simula Algol68 1970 Pascal Prolog Smalltalk C ML 1980 Le langage Fortran a introduit les expressions symboliques, les sous programmes avec des paramètres. Cobol, lui insère la description de donnée, c ’est à dire des types. Le Fortran est très utilisé pour les calculateur, tandis que Cobol est utilisé dans le cadre commercial des donnée (banque, assurance). Le langage Pascal est apparu dans les années 70, il est apparu comme simple, facilement implémentable. C ’était le premier langage avec des structures de contrôle assez riches, des types de données variés et la possibilité de définir de nouveaux types. Ada est apparu dans les années 80, a introduit les génériques et les pacquages. ML fut initialement développé par Robin Milner et d'autres personnes dans les années 1980 à l'Université d'Edimbourg, pour le système de preuves formelles LCF. R. Milner rencontrait des difficultés avec le système de typage de LISP qui permettait de « prouver » des assertions fausses. ML (Méta langage) est un langage fonctionnel impur, signifiant par là qu'il est possible de programmer en impératif, et que par conséquent, peut être sujet à des effets de bord, contrairement à des langages purement fonctionnels comme Haskell. ML a été standardisé en 1983, puis révisé en 1997, le langage résultant s'appelant SML (Standard ML), notamment implémenté dans Standard ML of New-Jersey (SML/NJ). En parallèle, des équipes françaises ont développé Objective Caml, dont la popularité dans la communauté ML internationale est maintenant très grande. Ada Miranda L. logiques L. Impératifs et procéduraux L. orientés objects L. fonctionnels

27 Langage de description d’algorithme
Chap. 1 : Niveaux de description Langage de description d’algorithme Algorithme valeurAcquise() Données : sommInitiale, taux : réel; Résultat : valeurAcquise : réel; Variables : intérêts : réel; début intérêts  sommeInitiale * taux ; valeurAcquise  sommeInitiale + intérêt; retourner valeurAcquise; fin Nous faisons le choix d’une description en deux blocks : le block d’identification (nom, type de données, type du résultat, variables utilisées) et le block d’instructions encadré par les mots clés début et fin.

28 Mathématique : fonction calculable
Chap. 1 : Niveaux de description Mathématique : fonction calculable Définition : Une fonction f est calculable s’il existe un procédé systématique permettant à partir de la valeur « x », par une série de manipulations précises, de connaître «f(x)». En février 34, A.Church soulève la question suivante: Quel est l’ensemble d’outils, le kit d’opérations, nécessaire pour calculer les valeurs des fonctions calculables?

29 La thèse de Alonso Church
Chap. 1 : Niveaux de description La thèse de Alonso Church Les fonctions calculables avec le Kit algorithmique (L.D.A.) sont par définition les fonctions programmables. Thèse : Toute fonction calculable est programmable et réciproquement. Thèse de Church Remarque : La réciproque :Il est clair que toute fonction programmable (avec le kit) est calculable (par algorithme discret d’étapes successives). L’implication : jusqu’à présent personne n’a concocté de contre-exemple, c’est à dire une fonction calculable, intuitivement algorithmique dont on ne pourrait écrire le programme avec le petit langage proposé. L’intérêt de ce type de résultat est qu’il correspond aujourd’hui à une définition des fonctions calculable, ou intuitivement algorithmique. C’est l’ensemble des fonctions programmables avec le kit. Question : Que penser aujourd’hui des fonctions calculables qui sont programmées avec des langages de haut niveau, et semble donc nécessiter un kit plus important pour être programmer? Est-ce à dire que des langages plus puissants augmenteraient le nombre de fonctions calculables?

30 Chap. 1 : Niveaux de description
Pour résumer Nous avons décrit un micro ordinateur comme composé d’une mémoire, d’un C.P.U. et d’un ensemble d’entrée/sortie. La fonction d’un ordinateur est d’exécuter des instructions sur des données. La mémoire d’un ordinateur peut être vu comme un ensemble de mots, composés de bits. D’un point de vue symbolique la mémoire est un espace de stockage composés de cases (allouée, vide ou pleine). Un programme est composé d’un ensemble d’instructions et il existe plusieurs niveaux de description de ces programmes : du langage machine au langage algorithme (L.D.A.).

31 Concepts de valeur et de type
Chapitre 2 Les données sont le principal matériel des programmes. Les données sont au moins aussi importantes que le programme lui-même. Les programmes sont la pour traiter les données telle que un répertoire téléphonique, un dictionnaire, les données géologiques collectées par un satellite. Dans ce chapitre nous allons étudier les différents types de données que l ’on aura à manipuler. Concepts de valeur et de type Olivier Raynaud Université Blaise Pascal

32 Chap. 2. : Concept de type et de valeur
Valeurs ... Définition : Une valeur est toute chose qui peut être évaluée, stockée, intégrée dans une structure de données, passée comme argument à une procédure ou une fonction, retournée comme le résultat d ’une fonction etc. Les notions de valeur et de stockage sont les deux supports principaux de la donnée.

33 Classification Principe de complétude : aucune opération ne devrait
Chap. 2. : Concept de type et de valeur Classification Valeur de 1ière classe : elles peuvent être évaluées, affectées, paramètres de fonctions ou procédures, composants de valeurs composées … Valeur de 2ième classe : ces valeurs admettent des restrictions d’utilisation. Principe de complétude : aucune opération ne devrait admettre arbitrairement de restrictions dans le type des valeurs évoquées. Prenons l ’exemple du Pascal, valeurs primitives (ou atomiques): valeur de vérité, caractère, énumérant, entier, nombre réel… valeurs composées: enregistrement, tableau, ensemble, fichier. Pointeurs: Référence à des variables. Procédure et fonction. Les deux dernières lignes peuvent surprendre car on ne peut les incorporer dans des structures de données, mais comme on peut les passer en paramètre d ’une fonction on les ajoute à la liste. Ce principe de complétude ne doit pas être un dogme, mais des langages admettent ce type de restriction avec peu de justifications.

34 En C trier(v, n, compare, echange) char *v[]; int n;
Chap. 2. : Concept de type et de valeur En C Valeur de 1ière classe : valeurs primitives et pointeurs. Valeur de 2ième classe : valeur composée, référence à des variables, fonction et procédure. trier(v, n, compare, echange) char *v[]; int n; int (*compare)(), (*echange)(); { …(*compare)(v[i], v[i+1])… …(*echange)(&v[i],&v[i+1])… } En C tous les arguments des fonctions sont passés par valeur (par l’intermédiaire de variables provisoire entassées dans la pile). La fonction appelée ne peut pas modifier une variable dans le programme appelant. Ainsi si l’on souhaite pouvoir mettre à jour une variable on doit fournir à la fonction l’adresse de cette variable en utilisant un pointeur sur cette variable (cf. page 26 [KR87]) En C Avec une « structure » ou une « union » calculer son adresse ou nommer un de ses membres (avec l’opérateur .). Avec une fonction on ne peut que soit l’appeler ou rechercher son adresse. Référence à des variables : une référence est une valeur de type adresse qui ne peut être stockée autrement que par un pointeur. Procédure et fonction : Une fonction ou une procédure ne peut être stockées dans une structure de données mais l’on peut définir des variables qui pointent vers ces fonctions. L’exemple de code donné définit la fonction « trier » de paramètre un tableau de pointeurs sur des caractères, un entier n et deux fonctions de comparaison et d’échange. La fonction de trie exécutera la fonction dont les instructions sont stockées à l’adresse véhiculer par les variables « compare » et « echange ».

35 Chap. 2. : Concept de type et de valeur
… et Types Définition : Un type est un ensemble de valeurs dit cohérent (c’est à dire dont le comportement par rapport à un ensemble d’opérations est similaire) . Ainsi nous dirons que « v » est une valeur de type T, autrement dit « v » appartient à T. Question: Tous les ensembles de valeur peuvent-ils être vu comme des types? Par exemple l ’ensemble {13, rue, lundi} ne peut être un type. Chaque langage de programmation admet des types dits atomiques, et d ’autres dits composites.

36 Types primitifs/composés
Chap. 2. : Concept de type et de valeur Types primitifs/composés Définition : Un type primitif est un ensemble de valeurs dites primitives (ou atomiques) qui ne peuvent être décomposées. Définition : Un type composé est un type dont les valeurs sont composées ou structurées à partir de valeurs simples. En fonction des types primitifs admis par le langage nous pouvons déjà avoir une idée des applications auxquelles il sera dédié. Par exemple, le langage Cobol utilisé largement pour traiter des données commerciales admet de nombreux types primitifs de chaînes de longueurs fixées par avance. Le Fortran, largement utilisé dans le cadre du calcul de précision admet différents types primitifs de réels de précisions différentes et des nombres complexes. Dans la plupart des langages nous avons les types: valeur de vérité:{false, true} entier:{… } réels:{…,-1.0,…,0.0, …, +1.0,…} caractères:{…, ’a ’, ’ b’,…, ’z ’,...} En pascal on peut créer soit même un nouveau type. type Mois = (jan, fev, mar,…,dec). Il s ’agit de la définition d ’un type par énumération, ses valeurs sont appelées énumérandes Question: Qu’est ce qu’une valeur simple? Une valeur simple est une valeur appartenant à un type primitif. Les langages de programmation admettent une variété importante de données structurées: tuples, records, union, tableau, ensemble, chaîne, liste, arbres, fichier, relation… En fait, toutes ces variétés peuvent être divisées en un petit nombre de concepts structurés comme: produit cartésien (tuples, records), union disjointe (union), mapping (tableau et fonctions), ensemble de parties (ensemble), type récursif (structures de données dynamiques comme les listes ).

37 Produit cartésien Plus formellement :
Chap. 2.: Concept de type et de valeur Produit cartésien Définition : le produit cartésien de deux ensembles S et T, noté « S x T », est l’ensemble de toutes les paires ordonnées dont la première valeur est prise dans S et la seconde dans T. Plus formellement : S x T = { (x,y) | x ∈ S et y ∈ T} |S x T| = |T| * |S| Note : autrement dit le produit cartésien associe entre elles des valeurs de deux différents types ou plus. Faire un dessin au tableau du produit cartésien avec S={u;v} et t={a,b,c}. Les types records ou tuples correspondent à un produit cartésien. En pascal on crée un produit cartésien de type record de la façon suivante: type Date = record m : Mois; j : 1..31; end Le type Date est donc un ensemble (de cardinal 12*31 =372) de paires dont le premier élément est un mois et le second un nombre compris entre 1 et 31. Nous avons dit qu’un type devait disposer d ’opérations à appliquer sur ses éléments. Question: Qu’elle sont les opérations sur ce type la? Ce sont les accès aux composants du record. Exemple: var cejourlà : Date; cejourlà.j :=29; cejourlà.m := fev.

38 Union disjointe Plus formellement :
Chap. 2. : Concept de type et de valeur Union disjointe Définition : l’union disjointe, ou la somme de deux ensembles E et F, notée « E + F», est l’ensemble de tous les couples (0,x) et (1,y) avec x dans E et y dans F Plus formellement : S + T = { gauche x | x∈S} ⋃ { droite y | y∈T} |E + F| = |E| + |F| Faire un dessin au tableau de l’union disjointe S={u;v} et v={a,b,c}.

39 En Pascal type précision = (exact, approx) nombre = record
Chap. 2. : Concept de type et de valeur En Pascal type précision = (exact, approx) nombre = record case precis : precision of exact : (ival : Integer); approx : (rval : Real) end L’ensemble des valeurs de ce type est nombre = Integer + Real Les valeurs possibles des variables de type nombre sont {…exact(-1), exact(0),exact(1)…} U {…approx(-1.0), …,approx(0.0),…,approx(1.0),…} En Pascal, l’union disjointe est implémentée par les variables de type « records ». Les opérations sur ce type de données sont les accesseurs : soit num une variable de type Nombre, supposons que sa valeur soit : (exact 7). monNombre.precis=exact; monNombre.ival=7; Cela peut générer des effets de bord gênant, si l’on affecte la valeur approx à monNombre.precis; en une seule instruction nous changeons la valeur de monNombre de (exact 7) à (approx indéfinie).

40 En C union u_tag{ int ival; float fval; char *pval; }; u_tag uval;
Chap. 2. : Concept de type et de valeur En C union u_tag{ int ival; float fval; char *pval; }; u_tag uval; L’intérêt de définir un type de genre « union » est de disposer d’un type unique qui puisse contenir différents types de valeur. En C, on ne conserve pas l’information concernant le type de l’objet de type u_tag. En C nous aurions les instructions suivantes : La variable uval doit être suffisamment large pour stocker n’importe lequel de ces trois types. C’est à la charge du programmeur de garder trace du type qui est stocké au moment voulu. Soit u_type la variable utilisée pour stocker le type de la variable uval: if (u_type == int) print uval.ival; else if (u_type == FLOAT) print uval.fval; …

41 « Les fonctions » (ou mapping)
Chap. 2. : Concept de type et de valeur « Les fonctions » (ou mapping) Définition : Une fonction de S dans T associe à chacun des objets de S un objet de T. On la note : f: S -> T. | S ->T | = |T||S| On appelle domaine (resp. image) d’une fonction, et l’on note dom(f) (resp. im(f)) la collection de ses arguments (resp. de ses valeurs). Proposer différents mapping de S={u,v} dans T={a,b,c}. Question : combien y ’a-t-il de mappings de S dans T? #T puissance #S. La notation # représente le cardinal d ’un ensemble. Question : Quels sont les types composés connus pouvant être caractérisés par un mapping? Les fonctions et les tableaux.

42 Les tableaux comme « mapping »
Chap. 2. : Concept de type et de valeur Les tableaux comme « mapping »  Les tableaux permettent d’implémenter des fonctions dont le domaine de définition est discret et fini. Conventionnellement, le tableau permet de mettre en correspondance l’ensemble des indices du tableau (ensemble fini, discret, de taille raisonnable) avec l’ensemble des valeurs contenues dans le tableau. Question: Qu ’est ce que l ’ensemble de départ dans la majorité des cas? Ils ’agit de l ’ensemble d ’index dans l ’ensemble des composants. L ’ensemble d ’index est souvent un intervalle d ’entiers commençant par 0 ou 1.

43 Chap. 2. : Concept de type et de valeur
En Pascal En pascal la déclaration : array[S] of T défini un mapping de l’ensemble S dans l’ensemble T; type couleur = (rouge, vert, bleu); pixel = array [couleur] of 0..1 Une valeur possible du type pixel est : {rouge → 0; vert → 1, bleu → 0} Question :nous avons dit qu ’un type était un ensemble de valeurs, quels sont les éléments du type Pixel défini ci-dessus? Un de ces éléments est le mapping: {red->0, green->0, blue->0} A noter :L ’ensemble des index doit être discret et fini.

44 Les fonctions comme « mapping »
Chap. 2. : Concept de type et de valeur Les fonctions comme « mapping » Les fonctions définies par un algorithme, qui à toute valeur de S (l’argument) associe une valeur de T (le résultat), est une implémentation possible de la notion de fonction au sens « mapping ». La distinction sémantique entre les tableaux et les fonctions est la même qu’entre se souvenir d’une solution ou calculer la solution. La différence entre la fonction du langage et la fonction mathématique est que notre fonction peut avoir accès à des variables non locales comme la date, un nombre aléatoire etc. Ne pas confondre les 2 types de fonction. En informatique on parlera de fonction abstraite pour éviter la confusion.

45 {0 → vrai; +/- 1 → faux, +/- 2 → vrai, +/- 3 → faux}
Chap. 2. : Concept de type et de valeur En Pascal function pair? (n :integer) : boolean begin pair? := (n mod 2 = 0) end Cette fonction implémente un mapping de l’ensemble des entiers relatifs dans l’ensemble des valeurs de vérité : {0 → vrai; +/- 1 → faux, +/- 2 → vrai, +/- 3 → faux} Question: Énumérer les éléments de l’ensemble : {0->true, +-1 ->false, +-2 -> true...} Exemple en Pascal Il s ’agit d ’un mapping, c ’est à dire d ’un type. function even (n:integer) : booléan; begin even := (n mod2 = 0) end Proposer une autre fonction pour implanter le même mapping. fonction even (n:integer) : booléan; begin n := abs(n); while n > 1 do n := n -2;even := (n = 0) Question :nous avons dit qu ’un type était un ensemble de valeurs, quels sont les éléments du type Pixel défini ci-dessus? Un de ces éléments est le mapping: {red->0, green->0, blue->0} A noter :L ’ensemble des index doit être discret et fini.

46 Les types récursifs T = … T …
Chap. 2. : Concept de type et de valeur Les types récursifs Définition : Un type récursif est un type dont les valeurs sont composées à partir des valeurs du même type. L’ensemble des valeurs d’un type T récursif peut être défini par une équation de la forme : T = … T … La cardinalité d’un type récursif est infinie. Nous ne pouvons donc pas énumérer toutes les valeurs d’un type récursif. Un type récursif est défini en terme de lui-même. Les listes sont des types récursifs. b)Un solution à l’équation récursive ci-dessus peut être déterminée de façon itérative : La première approximation consiste un remplaçant l’ensemble vide à T dans la partie droite de l’équation. Ensuite substitué T, toujours à droite par la solution obtenue à l’étape précédente. Et ainsi de suite. c)Question: comment évaluer la dimension de l’infini de ce type (dénombrable ou non)?

47 Chap. 2. : Concept de type et de valeur
Exemple des listes Définition : Une liste est une séquence de valeurs de taille quelconque. Son nombre de composants est appelé la longueur de la liste. La seule liste n’ayant aucun composant est appelée la liste vide. Supposons que l’on désire définir un type L dont les valeurs sont des listes de symboles de l’ensemble S. L’ensemble des valeurs de ce type peut être défini de façon récursive par l’équation : L = Unité + (S x L) Exercice : Définissez le type liste d’entiers: (1) Liste-Entiers = Unit + (Entier x Liste-Entiers) autrement dit (2) Liste-Entier = {nil()} + {cons (i,l) | i un entier, l une Liste-Entiers} autrement dit (3) Liste-Entiers = {nil} U {cons(i,nil) | i entier} U {cons(i,cons(j,nil)) | i,j entiers} U … Discussion Il est clair que ces ensembles (2 et 3) sont bien solutions de l’équation (1). Ce sont deux façons d’écrire l’ensemble des listes finies d’entiers. Mais il existe un super ensemble de (2 ou 3) qui vérifie aussi l’équation (1). C’est l’ensemble de toutes les listes d’entiers finies ou infinies. Nous ne tiendrons pas compte de cette solution puisque notre intérêt se porte sur les valeurs calculables pour une machine, or des listes infinies ne sont pas manipulables en temps fini par une machine.

48 Chap. 2. : Concept de type et de valeur
Exemple des strings Définition : Un string est une séquence de caractères. Ce type de données est disponible dans tous les langages de programmations modernes. Pourtant aucun consensus n’existe sur la classification des strings. a) Les strings sont elles des valeurs primitives ou composées? b) Quels opérations seront disponibles pour le traitement des strings? Les opérations sur les Strings: Test d’égalité, concaténation, caractère ou substrings sélection, ordre lexicographique … Le choix pour Pascal et ADA sont les tableaux pour implémenter les strings. Miranda et Prolog font le choix des listes de caractères. En C il s’agirait d’un tableau de caractères

49 Exemple de type récursif (ML)
Chap. 2. : Concept de type et de valeur Exemple de type récursif (ML) Considérons la déclaration de type : Datatype inttree = leaf of int / branch of ( inttree * inttree ) L’ensemble des valeurs de ce type peut être défini de façon récursive par l’équation : inttree = integer + (inttree * inttree ) Des exemples de valeurs : Leaf 11 Branch (branch (branch (leaf 5, leaf 7), leaf 9) , branch(leaf 12, leaf 18)) ML signifie méta langage. Par le processus de résolution donné précédemment nous obtenons l’ensemble suivant : {leaf i | i entier} U { branch (leaf i, leaf j) | i,j entiers} U { branch (leaf i, branch (leaf j, leaf k)) | i,j,k entiers} U { branch (branch (leaf j, leaf k) leaf i) \ i,j,k entiers} U { branch (branch (leaf i, leaf j) branch (leaf k, leaf l) | i,j,k,l entiers}

50 Type récursif vs Pointeur
Chap. 2. : Concept de type et de valeur Type récursif vs Pointeur Définition : Un pointeur est une variable qui contient l’adresse d’une autre variable [KR78] Tous les langages impératifs proposent des pointeurs plutôt que des types récursifs. Les raisons sont la sémantique et l’implémentation de l’affectation. Les pointeurs peuvent être utilisés pour implémenter des types récursifs, la manipulation des pointeurs reste néanmoins délicate. L’utilisation des pointeurs est délicate : Considérons l’affectation de pointeur suivante : p^.tail := q., nous ne pouvons dire quelle liste sera physiquement changée, peut être introduisons nous un cycle, ou mettons nous à changer toute la structure de donnée. ‘premiers := impaires’ ‘Premier’ pointe maintenant sur la même liste que ‘impaire’. La liste est partagée par les deux variables. Toute mise à jour de l’une change l’autre. Supposons un langage proposant un type récursif: Var premiers, impaires : list of integer Comment interpréter l’affectation : ‘premiers := impaires ’?

51 En C Comment interpréter s := t ? Soit x de type entier :
Chap. 2. : Concept de type et de valeur En C Soit x de type entier : int x; int *px; L’opérateur & nous donne l’adresse d’un objet : px := &x L’opérateur * retourne le contenu stocké à l’adresse de son opérande : int y := *px autrement dit y:=x char s[]; char t[] Comment interpréter s := t ?

52 Chap. 2. : Concept de type et de valeur
Les systèmes de type Le regroupement de données dans un type permet de décrire les données de façon efficace. Définition : Pour assurer le bon déroulement des opérations, l ’implémentation du langage doit assurer une vérification du type des opérandes. Bien que la vérification du type doit se faire avant l ’exécution de l’opération elle même, il y ’a un degré de liberté très important sur le moment ou aura lieu cette vérification. Au moment de la compilation ou au moment de l ’exécution. Ce choix permet de classer les langages de programmation en 2 catégories: Les langages à typage dynamique et les langages à typage statique.

53 Chap. 2. : Concept de type et de valeur
Vérification de type Typage statique : Dans un langage à typage statique, toutes les variables et paramètres ont un type fixé qui est choisi par le programmeur. Typage dynamique : Les variables ou les paramètres n ’ont pas un type prédéfini, et peuvent désigner des valeurs de différents types à des moments différents. Seules les valeurs ont un type prédéfini. Typage statique :Ainsi le type de chaque expression peut être déduit et chaque opération peut subir une vérification de type au moment de la compilation. Question : Citez les langages de haut-niveau connus pour être à typage statique. La plupart d ’entre eux. Question : A quel moment doit-on effectuer la vérification de type? Immédiatement avant l ’exécution de l ’opération, ce moment est appelé run-time. Question : Citer des langages à typage dynamique Réponse :Lisp et smalltalk. Procédure readlitéral (var item); Begin read a string; if the string constitue un entier littéral then item := la valeur numérique du string else item := le string lui même end La commande suivante peut être utilisée pour lire une date de la forme ‘   ’ ou ‘ 1983 Feb 23 ’ avec le code: read(y); readliterral (m); read(d); if (m >=1) and (m <=12) then return else if m = « JAN » then m :=1 else if m = «  FEB» then m := else… Inconvénient: l ’exécution d ’un programme est ralenti par le run-time. En effet, puisque la vérification de type est faite au moment de l’exécution chaque valeur doit être taggée par son type pour l’identifier. Cela coût du temps et de l’espace mémoire. La sécurité est moins assuré. Or le débogage coût très cher à la réalisation d ’un logiciel. Mais il y a plus de flexibilité pour le typage dynamique.

54 Pour résumer Chap. 2. : Concept de type et de valeur
Nous avons défini la notion de valeur comme toute chose manipulable et évoqué le principe de complétude pour les valeurs qui limite les contraintes non justifiées dans leur utilisation. Nous avons défini de la notion de type comme un ensemble d’objets cohérents. Les langages de programmation proposent beaucoup de types composés mais les concepts mathématiques sous jacents sont peu nombreux : produit cartésien, union disjointe, fonction, type récursifs. La vérification de type peu se faire soit à la compilation (typage statique) ou au moment de l’exécution (typage dynamique).

55 Types récursifs et schéma d’induction
Chapitre 3 Types récursifs et schéma d’induction Olivier Raynaud Université Blaise Pascal

56 Cellules isolées Définition : « Cellule isolée » 14 19 2 6 …
Chap. 3. : Type récursifs et schéma d’induction Cellules isolées Définition : « Cellule isolée » Un appellera « cellule isolée » un ensemble composé d’un ensemble d’éléments d’un ensemble S à définir, d’un ensemble de pointeurs NULL et de façon optionnelle d’un ensemble de drapeaux. 14 19 2 6 Le contexte permet de définir l’ensemble S, le nombre de contenus, et le nombre de pointeurs et les drapeaux. On appelle type de la cellule le triplet (taille de l’ensemble des éléments de S, nombre de pointeurs, nombre de drapeaux).

57 Chap. 3. : Type récursifs et schéma d’induction
Les listes chaînées Définition : Une liste chaînée est composée d’une suite finie de cellules (ou couples) formées d’un élément et de l’adresse (ou référence) vers l’élément suivant. Les cellules d’une liste doublement chaînée admettent aussi un pointeur vers le précédent élément élément Il s’agit d’une structure de base de la programmation, très ancienne. Un usage systématique en est fait en LISP (List Processing) conçu par Jhon MacCarthy en 1960. La recherche d’un élément dans une liste s’apparente à un classique « jeu de piste » dont le but est de retrouver un objet caché. On ne connaît pas d’information globale sur la suite puisque l’on en connaît que le successeur d’un élément. C’est ce caractère local qui permet une grande souplesse d’organisation. On appelle usuellement cellule un couple (élément, adresse). Une liste est donc une adresse vers la première cellule. Important : l’adresse du champs suivant de la dernière cellule est NUL. élément élément

58 Les opérations élémentaires
Chap. 3. : Type récursifs et schéma d’induction Les opérations élémentaires Soit l une liste : maListe <- new liste(monContenu, monSuivant, monprecedent) Accesseurs : maListe.élément; maListe.suivant; maListe.précédent. Opérations usuelles : maListe.insérer(x) insère un contenu en tête de liste; maListe.rechercher(x) rechercher un contenu dans la liste; maListe.supprimer(x) supprimer un contenu dans la liste. On peut interpréter maListe comme une cellule. Nos accesseurs « élément » et « suivant » sont souvent mentionnés dans la littérature sous les noms de « tête » et de « queue ».

59 Les listes chaînées circulaires
Chap. 3. : Type récursifs et schéma d’induction Les listes chaînées circulaires Définition : Une liste chaînée circulaire admet la même structure qu’une liste classique mais le champs « suivant » de la dernière cellule contient l’adresse de la première cellule. élément élément On retrouvera les même besoins en opérations mais l’on peut ajouter l’opération qui vérifie si une liste donnée est un singleton.

60 Schéma inductif de construction
Chap. 3. : Type récursifs et schéma d’induction Schéma inductif de construction Définition (Schéma d’induction < B,  >) Soient U un univers et B  U appelé base. Soit  une famille d’opérations sur U. On appelle fermeture inductive E de B par  la partie E de U définie par le schéma : Base : B  E; Règle : Pour tout f   et pour tout x1,…,xn dans E, où n est l’arité de f, si x=f(x1,…,xn) est défini alors x  E; Fermeture : E est la plus petite partie de U (au sens de l’inclusion) qui contient B et qui est stable par rapport à . Phase d’initialisation ou base qui consiste en une description d’un ensemble primitif B. Les éléments de B sont appelés les atomes ou les générateurs de E; Phase d’induction ou de règles qui consiste en une description d’un ensemble d’opérations ou règles de production permettant de combiner des objets déjà construits pour en obtenir de nouveaux; Phase de fermeture, qui comporte une clause permettant de délimiter E [XUO92]

61 Chap. 3. : Type récursifs et schéma d’induction
La notion de classe… Définition : « La classification, ou formation de classe, est une opération intellectuelle par laquelle nous imaginons avoir rassemblé certaines choses en un groupe. Un tel groupe est appelé classe. » [Ca66]

62 Les arbres Définition (par induction)
Chap. 3. : Type récursifs et schéma d’induction Les arbres Les arbres représentent un ensemble de données structurées hiérarchiquement. Définition (par induction) La classe des arbres est définie par le schéma : Base : l’arbre vide et l’ensemble des cellules isolées. Règles : soit F une famille d’arbres et r une cellule isolée alors la structure de racine r, et dont les fils sont des éléments de F est un arbre. Nous distinguerons plusieurs types d’arbres : les arbres libres, les arbres enracinés, les arbres binaires…

63 Parcours Deux catégories de parcours :
Chap. 3. : Type récursifs et schéma d’induction Parcours La recherche d’un éléments ou l’énumération de l’ensemble des éléments d’une structure de données se fait souvent par un parcours de la structure. Deux catégories de parcours : Le parcours en profondeur explore l’arbre branches après branches; Le parcours en largeur explore l’arbre par niveau de profondeur.

64 Chap. 3. : Type récursifs et schéma d’induction
Quelques définitions Définition : Soit T un arbre et r sa racine, pour tous nœud x il existe un chemin unique de x à r; Tout nœud y sur ce chemin est appelé ancêtre de x et x descendant de y; Le degré d’un nœud est le nombre de ses enfants directs et un nœud sans enfant est une feuille, un nœud qui n’est pas un feuille est appelé nœud interne; La profondeur d’un nœud correspond au nombre d’arcs entre la racine et ce noeud. La plus grande profondeur que puisse avoir un nœud quelconque d’un arbre correspond à la hauteur de cet arbre. La hauteur d’un arbre est la longueur maximale d’un chemin reliant la racine à une feuille; C’est-à-dire le nombre d’arêtes.

65 Chap. 3. : Type récursifs et schéma d’induction
… et de sous classe Définition: Nous pouvons penser à la classe « chose » et supposer que nous lui avons enlevé toutes les choses qui ont une qualité donnée que ne possède pas la classe en sa totalité. Cette qualité est dit particulière à la classe ainsi formée… [Ca66] Cette classe ainsi formée deviendra donc une sous classe de la classe chose

66 La classe des arbres binaires
Chap. 3. : Type récursifs et schéma d’induction La classe des arbres binaires Définition (par induction) : La classe des arbres binaires est définie par le schéma : Base : l’arbre vide et l’ensemble des cellules isolées Règles : soient r une cellule isolée et 2 arbres binaires (dont l’un des deux est non vide) alors l’arbre de racine r ayant pour fils chacun des deux arbres binaires est un arbre binaire. Soient A et A’ les deux arbres binaires et r une cellule isolée disposant de deux accesseurs de voisinage que l’on appelle ici sag et sad. Nous obtenons r.sag = A et r.sad= A’.

67 Parcours en profondeur
Chap. 3. : Type récursifs et schéma d’induction Parcours en profondeur Pour les arbres binaires il existe 6 types de parcours en profondeur : x x x 1 2 3 sAG sAD sAG sAD sAG sAD 2 1 infixe préfixe 1 postfixe

68 Représentation des arbres binaires
Chap. 3. : Type récursifs et schéma d’induction Représentation des arbres binaires r r 1 1 2 2 3 3 Deux arbres binaires différents, ainsi un arbre binaire n’est pas simplement un arbre ordonné dont tous les nœud sont d’arité au plus deux. A gauche : ( 0, 1, ( (0, 3 , 0), 2, 0 )) et à droite : ( (0, 2, (0, 3, 0)), 1, 0 ). Ici on montre l’orientation à partir de la racine, par la suite les arcs ne seront plus mentionnés. ( 0, 1, ( (0,3,0), 2, 0 ) ) ( (0,2,(0,3,0)), 1, 0 )

69 Principe d’induction structurelle
Chap. 3. : Type récursifs et schéma d’induction Principe d’induction structurelle Théorème : Soit E la fermeture d’un schéma < B,  >. Prouver que tout élément de E admet une propriété P, revient à prouver que : Base d’induction : tout x  B vérifie P; Étape d’induction : pour tout f de  et pour toute séquence (x1,…,xn) d’éléments de E qui vérifient P, si x=f(x1,…,xn) est défini alors x vérifie P. [XUO92] Démonstration : Soit F l’ensemble des éléments de E qui vérifient P. D’après l’étape de Base B est inclus dans F. Par l’étape d’induction on montre que chacune des règles de production conservent la propriété P. Autrement dit on montre que F est stable par rapport à . D’après la clause de fermeture qui définit E, on peut écrire que F= E puisque E est minimum au sens de l’inclusion. Ce qui démontre le théorème.

70 Application du principe d’induction
Chap. 3. : Type récursifs et schéma d’induction Application du principe d’induction Proposition : Soit A un arbre binaire, on note nbF(A) son nombre de feuilles, alors le nombre de nœuds de degré 2 de A est égal à nbF(A) - 1. Proposition : Soit A un arbre binaire de hauteur h et de n nœuds, alors ⌊log n⌋ ≤ h < n . Proposition 1 : soit p la propriété « soit A un arbre binaire, nbDegre2(A)=nbf(A)-1 ». 1)Montrons que p est vraie pour les éléments de la base; 2)Soient A1 et A2 qui vérifie p, soit A produit par OmegaSigma à partir de A1 et A2, montrons que A vérifie p : 2 cas : si A2 est nil; alors nbd2(A)=nbd2(A1)=nbf(A1)-1=nbf(A)-1; Sinon, nbd2(A)=1+nbd2(A1)+nbd2(A2)=1+nbf(A1)-1+nbf(A2)-1=nbf(A)-1. 3)Puisque p est vrai pour les éléments de la base et que p reste vrai par application de Omega alors p est vrai pour tout élément de la classe. Proposition 2 : La seconde proposition trouve plusieurs formes. Soit en fonction de la hauteur, telle qu’elle est exprimée ci-dessus ou sur la profondeur. On obtient alors l’inégalité suivante : log n < h+1 ≤ n. C’est sous cette seconde forme que nous la démontrons. On vérifie que la propriété est vraie sur les premiers exemples de la base. Soient A1 et A2 deux arbres de hauteur respectives h1 et h2 tel que A.sag = A1 et A.sad=A2. Par hypothèse d’induction nous avons : log n1 < h1+1 et log n2 < h2 +1 Autrement dit n1 < 2h1+1 et n2 < 2h2+1. Et encore n1 ≤ 2h et n2 ≤ 2h Par construction nous avons : n = n1 + n2 + 1 ≤ 2h h ≤ 2h h2+1 ≤ 2* 2 max (h1,h2) ≤ 2h+1 -1 On en déduit finalement que n < 2h+1 c’est-à-dire que log n < h+1 CQFD. Question : Démontrer par le principe d’induction structurelle que les propositions précédentes sont vraies.

71 Arbres binaires complets ou presque
Chap. 3. : Type récursifs et schéma d’induction Arbres binaires complets ou presque Définition : un arbre binaire est dit presque complet (ou tassé) si tous les niveaux sont remplis et si le dernier est remplis de gauche à droite. Définition : un arbre binaire est dit complet si tous les niveaux sont remplis (toutes les feuilles sont alors de même hauteur). Soit p la propriété « soit A un arbre binaire complet et n son nombre de nœuds internes, alors le nombre de feuille de A est n+1 ». 1)Montrons que p est vraie pour éléments de la base; 2)Soit A1 un arbre binaire complet vérifiant p, soit A construit par application de Omega à partir de A1, montrons que A vérifie p. Nbf(A)=2*nbf(A1)=2*(nbI(A1)+1)=[2*nbI(A1)+1 ]+1 = nbI(A)+1; 3)Puisque p est vraie pour les éléments de B et que p reste vraie par la construction Omega alors p est vraie pour tous les éléments de la classe. Proposition : Soit A un arbre binaire complet de n nœuds internes, le nombre de feuilles de A est n+1.

72 Chap. 3. : Type récursifs et schéma d’induction
Notion de chemin Définition : La longueur du chemin intérieur d’un arbre est la somme, restreinte à tous les nœuds internes de l’arbre, de la profondeur de chaque nœud. Définition : La longueur du chemin extérieur d’un arbre est la somme, restreinte à toute les feuilles de l’arbre, de la profondeur de chaque feuille. Ici on appelle profondeur le nombre d’arcs de la racine à un nœud.

73 Application du principe d’induction
Chap. 3. : Type récursifs et schéma d’induction Application du principe d’induction Proposition : Soit un arbre binaire complet de n nœuds internes, soit i la longueur de son chemin intérieur et e la longueur de son chemin extérieur, alors e = i + 2n. Question : Démontrer par le principe d’induction structurelle que la proposition précédente est vraie.

74 Application du principe d’induction
Chap. 3. : Type récursifs et schéma d’induction Application du principe d’induction Base Règle de construction n=0 i=0 e=0 n=1 i=0 e=2 Isomorphisme On vérifie que la proposition est vrai sur les premières instances. Soit A la réunion de deux sous arbres isomorphes à A1. Par hypothèse A1 vérifie la proposition. On a donc : eA1 = iA1 + 2nA1. Autrement dit on a eA1 - iA1 = 2nA1 On montre par construction que : iA = 2* (iA1 + nA1) En effet il faut ajouter à iA1 une unité par nœud de A1, ensuite on multiplie par 2 pour chacun des 2 sous arbres. eA = 2* (eA1 + nA1 + 1) en effet le nombre de feuille de A1 est nA1+1 nA = 2 * nA1 + 1; Ainsi eA – iA = 2 * (eA1 + nA1 + 1 – iA1 – nA1) = 2*(eA1 – iA1 +1). Par hypothèse d’induction on obtient eA – iA = 2* (2nA1 + 1) = 2* nA. CQFD

75 Les arbres complets d’arité k
Chap. 3. : Type récursifs et schéma d’induction Les arbres complets d’arité k Définition (par induction) : la classe des arbres complets d’arité k est définie par le schéma suivant : Base : les cellules isolées sont des arbres complets d’arité k de hauteur 0; Règle : soit r une cellule isolée et k arbres complets d’arité k de hauteur n, alors l’arbre de racine r ayant pour fils chacun des k arbres complets est un arbre complet d’arité k de hauteur n + 1.

76 Application du principe d’induction
Chap. 3. : Type récursifs et schéma d’induction Application du principe d’induction Proposition : Soit A un arbre complet d’arité k de hauteur h, le nombre de feuilles de A est kh, et le nombre de nœud internes est ( kh – 1 ) / ( k – 1 ) Question : Démontrer par le principe d’induction structurelle que la proposition est vraie.

77 Application du principe d’induction
Chap. 3. : Type récursifs et schéma d’induction Application du principe d’induction Règle de construction Base h=n+1 k ….. h=0 h=1 k Proposition : Soit A un arbre complet d’arité k de hauteur h, le nombre de feuilles de A est k^h, et le nombre de nœud internes est ( k^h – 1 ) / ( k – 1 ); On vérifie que le nombre de feuilles et que le nombre de nœuds internes des arbres de la base vérifient la propriété; Soit A’ un arbre complet d’arité k de hauteur h+1. Montrons que h(A’) = kh+1 . Les feuilles de A’ sont les feuilles de chacun des A1…Ak. Ainsi nbF(A’) = nbF(A1). … + nbF(Ak) = k * kh = k(h+1). CQFD Montrons que nbNI(A’) = (kh+1)/(k-1) Les nœuds internes de A’ sont les noeuds internes de chacun des A1…Ak plus la racine. Ainsi nbNI(A’) = nbNI(A1). … + nbNI(Ak) + 1= k * (kh - 1) / (k - 1) + (k – 1)/(k-1) = (k(h+1) - k + k -1) / (k-1)= (k(h+1) -1 )/ (k-1). CQFD Question supplémentaire : montrer que pour k=2 nous avons n = 2^(h+1) - 1. Démonstration : n = nbI + nbF = (2^h - 1) + 2^h = 2^(h+1) - 1. h=n h=n

78 Les arbres binaires de recherche
Chap. 3. : Type récursifs et schéma d’induction Les arbres binaires de recherche Définition : un arbre binaire est un A.B.R. si pour tout nœud s, les contenus des nœuds du sous-arbre gauche de s sont inférieurs (≤) au contenu de s et les contenus du sous-arbre droit sont supérieurs (>) au contenu de s. Accesseurs : a.contenu; a.sAG; a.sAD. Opérations usuelles : a.insérer(x) : insère l’élément x dans l’arbre; a.maximum() et a.minimum() a.supprimer(x) : supprime un élément. a.rechercher(x) Les fonctions de recherche, minimum et maximum retournent des pointeurs sur les cellules correspondantes.

79 Exemple 16 14 19 8 8 Chap. 3. : Type récursifs et schéma d’induction
20 8 15 Attention, contrairement au « tas », il ne suffit pas de supposer que, pour tout nœud s de l’arbre, le contenu du fils gauche est inférieur et le contenu du fils droit supérieur. Construire un exemple au tableau en échangeant le dernier 14 en 13. 8 10 15

80 Définition par schéma d’induction
Chap. 3. : Type récursifs et schéma d’induction Définition par schéma d’induction Définition : (par induction ) la classe des arbres binaires de recherche est définie par le schéma suivant : Base : les cellules isolées sont des arbres binaires de recherche; Règle : soient r une cellule isolée et deux arbres binaires de recherche sAG et sAD (non tous 2 nuls), si le contenu de r est supérieur ou égal à maximum(sAG) et strictement inférieur à minimum(sAD) alors l’arbre (sAG, r, sAD) est un arbre binaire de recherche.

81 Chap. 3. : Type récursifs et schéma d’induction
Quelques questions Question : Montrer que le parcours infixe d’un arbre binaire de recherche fournit le contenu de ses nœuds par ordre croissant. Question : Que peut-on dire de la complexité des algorithmes de recherche, d’insertion ou de suppression dans un arbre binaire de recherche.

82 Chap. 3. : Type récursifs et schéma d’induction
Les « tas » Définition : un tas est un arbre binaire presque complet tel que pour tous nœuds n sauf la racine on a : n.pére.contenu ≥ n.contenu Accesseurs : t.contenu; t.fG; t.fD; t.pére Opérations usuelles : t.insérer(x) : insère l’élément x dans le tas; t.maximum() : retourne l’élément maximum; t.extraire() : supprime un élément maximum.

83 Implémentation par un tableau
Chap. 3. : Type récursifs et schéma d’induction Implémentation par un tableau 1 16 3 2 14 10 4 5 6 7 9 8 7 3 8 9 10 2 4 1 Un tas s’implémente facilement à l’aide d’un tableau. Les nœuds d’un arbre sont numérotés en largeur, de gauche à droite. Ces numéros sont des indices dans un tableau. 1 2 3 4 5 6 7 8 9 10 16 14

84 Les « tas » : relation de filiation
Chap. 3. : Type récursifs et schéma d’induction Les « tas » : relation de filiation L’implémentation d’un tas par un tableau admet quelques propriétés : racine : nœud 1; parent du nœud i : nœud( i Div 2); fils gauche du nœud i : nœud(2i ); fils droit du nœud i : nœud(2i + 1) Le fait que l’arbre soit tassé conduit à un calcul très simple des relations de filiation dans l’arbre.

85 Chap. 3. : Type récursifs et schéma d’induction
Pour résumer Nous avons défini la notion de cellule (des contenus, des pointeurs, des drapeaux). Nous avons alors montré comment construire des listes chaînées, simple, double, circulaire. Nous avons montré le lien entre définition récursive et définition par construction inductive (une base, des règles de production). Nous avons montré comment démontrer des propriétés sur des ensembles d’objets potentiellement infinis grâce au principe d’induction structurelle. Nous avons donné les spécifications des structures d’aBR et des tas.

86 Les types de données abstraits
Chapitre 4 Les types de données abstraits Olivier Raynaud Université Blaise Pascal

87 Chap. 4. : Type de données abstrait
Définition Un type de données abstrait est composé d’un ensemble d’objets, similaires dans la forme et dans le comportement, et d’un ensemble d’opérations sur ces objets. L’implémentation d’un T.D.A. ne suis pas de schéma préétabli. Il dépend des objets manipulés et des opérations disponibles pour leur manipulation.

88 Contraintes d’implémentation
Chap. 4. : Type de données abstrait Contraintes d’implémentation L’implémentation d’un type de données abstrait doit respecter deux contraintes : utiliser un minimum d’espace mémoire; exécuter un nombre minimal d’instructions pour réaliser une opération.

89 T.D.A. Ensemble dynamique
Chap. 4. : Type de données abstrait T.D.A. Ensemble dynamique Définition : On appelle ensemble dynamique e un ensemble fini d’éléments issus d’un ensemble discret (entiers, chaîne de caractères,…) et muni d’une relation d’ordre. Opérations : e.inserer(x) ajoute un élément x à e; e.supprimer(x) un élément x de e; e.rechercher(x) e.maximum() retourne l’élément maximum de e; e.minimum() retourne l’élément minimum de e; e.prédécesseur(x) e.successeur(x) La notion d’ensemble est un des piliers de la science des mathématique comme celle de l’informatique. Les ensembles mathématiques sont souvent stables « tandis que ceux manipulés par les algorithmes peuvent croitre, diminuer ou subir des modifications ». Il s’agit alors d’ensembles dynamiques. On distingue sur ces ensembles deux types d’opérations : Les requêtes et les opérations de modification (En SQL on parlera du L.M.D. (manipulation) et du L.D.D. (définition). Les aspects d’implémentation de ce T.D.A. sont laissés en exercice ou seront vus en séances de T.D.

90 Chap. 4. : Type de données abstrait
T.D.A. Dictionnaire Définition : On appelle dictionnaire un ensemble dynamique d dont on a restreint l’ensemble des opérations : Opérations : d.insérer(x) : insère l’élément x dans d; d.rechercher(x) : recherche l’élément x dans d; d.supprimer(x) : supprime l’élément x de d.

91 Dictionnaire : Implémentation
Chap. 4. : Type de données abstrait Dictionnaire : Implémentation Structure de données Rechercher Insérer Supprimer Tableau non ordonné O(n) O(1) Liste non ordonnée Tableau ordonné O(log n) Liste ordonnée Arbre de recherche O(h) Tas Dans le tableau on suppose que l’opération de suppression de contient pas la recherche. L’entier h désigne la hauteur de l’arbre. On voit que lorsque l’arbre est bien équilibré, c’est à dire lorsque la hauteur est proche du logarithme de la taille, les opérations sont réalisables de manière particulièrement efficaces. Question : démontrer que la hauteur d’un tas est majorée par log n. On propose ici une démonstration non récursive. Un arbre binaire presque complet admet une couche complète. Dans un arbre binaire complet on a : n= nbI + nbF = 2^(h+1) - 1. Ainsi n1 = ¨2^h - 1 ≤ n1 + n2 ≤ n. On obtient 2^h ≤ n +1 on en conclue que h ≤ log (n+1) d’où h est de l’ordre de O(log n). Le résultat optimal est h = pei ( log (n+1) ).

92 Chap. 4. : Type de données abstrait
T.D.A. Pile Définition : Une pile est un ensemble dynamique tel que la suppression concerne toujours le dernier élément inséré. Une telle structure est aussi appelé LIFO (last-in, first out). Opérations : p.empiler(x) insère un élément à l’entrée de la pile; p.dépiler() retourne et supprime l’élément en entrée de pile; Les termes d’ « empiler » et « dépiler » sont associés à la façon dont, par exemple, on range les assiettes.

93 Les piles : applications
Chap. 4. : Type de données abstrait Les piles : applications La pile d’exécution : les appels des méthodes dans l’exécution d’un programme sont gérés par une pile. Éditeur de texte : une pile est fournie par les éditeurs de texte évolués qui possèdent le couple d’actions « annuler-répéter ». Au sommet de la pile se trouve la dernière méthode appelée, dont l’exécution est en cours. Juste en dessous on trouve la méthode qui a appelé la méthode en cours, et ainsi de suite. Le fond de la pile est constitué de la méthode main. Lorsque la méthode en cours se termine, elle est enlevée de la pile d’exécution et le programme continue avec la méthode appelante. Au contraire l’appel d’une nouvelle méthode provoque l’empilement au sommet de la pile, de cette méthode. Dans une méthode récursive, la même méthode peut se trouver empilée plusieurs fois. Chaque action d’édition est empilée, et la commande undo défait la dernière action, celle qui se trouve au sommet de la pile. On peut imaginer une deuxième pile (en général ce n’est pas comme ça que ça marche) où sont empilées les actions que l’on vient d’annuler. Alors une commande undo empile l’action défaite sur la deuxième pile, et une commande redo l’enlève de la deuxième pile et la remet sur la première.

94 Les piles : Implémentation
Chap. 4. : Type de données abstrait Les piles : Implémentation On peut implémenter une pile par un couple composé d’un tableau et d’un entier. 1 4 12 8 9 14 20 5 6 2 5 Inconvénient majeur : il faut fixer à l’avance la taille maximale de la pile. Une pile contient donc un tableau d’entiers dont nous fixons la taille arbitrairement à une valeur constante. Seul le début du tableau est utilisé et un indice variable indique la hauteur de la pile, c’est à dire le nombre d’éléments présents dans la pile. Sommet = 0 indique que la pile est vide.

95 Chap. 4. : Type de données abstrait
T.D.A. File Définition : Une file est un ensemble dynamique tel que les insertions se font d’un coté (l’entrée de file) et les suppressions de l’autre coté (la sortie de file). Une telle structure est aussi appelé FIFO (first-in, first out). Opérations : f.enfiler(x) ajoute un élément en entrée de file; f.défiler() supprime l’élément situé en sortie de file.

96 Les files : applications
Chap. 4. : Type de données abstrait Les files : applications Les files d’attentes pour les systèmes de réservations, d’inscriptions, d’accès à des ressources… La gestion des files d’attente fait l’objet de modélisation par des outils statistiques tels que les chaînes de Markov.

97 Les files : Implémentation
Chap. 4. : Type de données abstrait Les files : Implémentation On peut implémenter une file par un triplet composé d’un tableau et de deux entiers. entrée 3 8 1 4 12 8 9 14 20 5 6 2 sortie 1 4 12 8 9 14 20 5 6 2 6 3 Les éléments présents dans la file ont pour ensemble de numéros l’intervalle semi-ouvert [sortie,entrée[ . L’intervalle est vide si sortie = entrée, mais il n’est pas nécessaire que d soit nul. Cet intervalle représente aussi le cas initial avec sortie=entrée=1. Avant de retourner un élément il faut toujours vérifier que entrée n’est pas égal à sortie. Pour distinguer cette situation du cas d’une file pleine, on s’interdit d’utiliser la totalité du tableau et on laisse toujours une entrée vide. Ainsi la file est pleine si entrée+1 = sortie mod n, où n est la taille de la file. Une autre technique consisterait à indiquer que la file est pleine par l’utilisation d’un booléen. Pour la gestion des erreurs il faut prévoir les cas d’insertion dans une file pleine et les cas de suppression dans une file vide. Inconvénient majeur : il faut fixer à l’avance la taille maximale de la file.

98 Les files : Implémentation
Chap. 4. : Type de données abstrait Les files : Implémentation On peut implémenter une pile par un couple de listes chaînées. début 2 . 7 . . 9 x L’avantage de cette implémentation est que la file n’est jamais pleine. La seule difficulté est l’ajout d’un élément. Il faut distinguer le cas de la file vide, où les deux attributs début et fin doivent être modifiés. fin

99 Comparaison d’implémentation
Chap. 4. : Type de données abstrait Comparaison d’implémentation Nous avons vu que l’implémentation par les tableaux impose de définir par avance la taille de la file. Ce qui n’est pas cas avec les listes chaînée. Quelque soit le choix d’implémentation, ce choix n’apparaît pas pour le programmeur puisqu’il n’aura accès à ce type de données que par l’intermédiaire d’un ensemble de méthodes. La file devient alors un type de données abstrait. Question : Une file à double entrées autorise des suppressions et des insertions à chaque extrémités. Ecrire les quatre procédures correspondantes avec des complexités de l’ordre de O(1). Montrer comment implémenter une file à l’aide de deux piles. Réponse : On dispose de deux piles qui jouent un rôle complètement symétrique. L’une des deux est toujours vide. Le sommet de pile P1 correspond à l’entrée de la file. Le sommet de la pile P2 correspond à la sortie de la file. Enfiler(x) Si (p2 est vide) alors empiler(p1,x) Sinon Tantque (p2 non vide) faire empiler(p1,dépiler(p2)) Ftq empiler(p1,x) Fsi Fin Défiler() Si (p1 est vide) alors dépiler(p2) Sinon Tantque (p1 non vide) faire empiler(p2,dépiler(p1)) dépiler(p2)

100 Chap. 4. : Type de données abstrait
T.D.A. Files de priorité Définition : Une file de priorité est une structure de données permettant de gérer un ensemble f d’éléments, chacun ayant une priorité associée appelée clé. Opérations : f.insérer(x,clé) : insère l’élément x dans f; f.maximum() : retourne l’élément de plus grande clé; f.extraireMax() : retourne et supprime l’élément de f de plus grande clé. Une file de priorité est une file dans laquelle l’insertion se fait en fonction d’une certaine priorité. Application : La planification de tâche sur un ordinateur à ressource partagées. Lorsque une tâche est terminée ou interrompue la tâche de plus grande priorité est choisie à l’aide de extraireMax(). Une tâche peut être ajoutée à tous moment à l’aide de insérer(x). On utilise aussi une file de priorité lorsque l’on désire simuler l’apparition d’événements. Chaque élément de la file représente un événement avec leur moment d’apparition. Il faut dans ce cas renverser l’ordre et disposer des fonction minimum() et extraireMin(). [CLR90]

101 File de priorité : Implémentation
Chap. 4. : Type de données abstrait File de priorité : Implémentation Structure de données Insérer() Maximum() extraireMax() Tableau non ordonné O(1) O(n) Liste non ordonnée Tableau ordonné Liste ordonnée Tas à étudier Réfléchir avec les étudiants sur les trois fonctions proposées par la structure de tas et montrer pourquoi elle semble parfaitement adaptée pour l’implémentation des files de priorité. Un tas : insertion(x); maximum(); extraire();

102 T.D.A. Famille d’ensembles
Chap. 4. : Type de données abstrait T.D.A. Famille d’ensembles Définition : Soit X un ensemble muni d’une relation d’ordre <x, on appelle collection (ou famille) un ensemble F de sous-ensembles de X. Opérations : c.insérer(s) : insère le sous-ensemble s dans c; c.appartient(s) : vérifie si le sous-ensemble s est dans c; c.supprimer(s) : supprime le sous-ensemble s de c.

103 Implémentation et complexité
Chap. 4. : Type de données abstrait Implémentation et complexité Question : Quelle structure de données permettrait de proposer des algorithmes pour les opérations d’insertion, de vérification d’appartenance et de suppression admettant une complexité indépendante de la taille de la famille?

104 Exemple a b e b d c c c d d d d e e e
Chap. 4. : Type de données abstrait Exemple a b e b d c c c d d d d e Remarque : Le nombre maximum de nœud de l’arbre T(F) est |A|*|F|. Notons que cette structure ne permet pas de stocker des mots puisque les mots contiennent des occurrences multiples de lettres et que les mots ne respectent pas l’ordre <a d’apparition des lettres. Nous verrons plus loin des exemples d’utilisation d’une telle structure. e e

105 L’arbre lexicographique
Chap. 4. : Type de données abstrait L’arbre lexicographique Définition : soit F une famille de sous-ensembles de X, nous associons à F un arbre T(F) lexicographique unique tel que : chaque arête de l’arbre est étiqueté par un élément de X; à chaque nœud notifié de l’arbre correspond un mot de F; à chaque mot de F correspond un chemin unique dans l’arbre tel que ce mot corresponde à la concaténation des étiquettes de ce chemin; l’ordre des arêtes d’un chemin coïncident avec l’ordre <x; l’ordre des arêtes sortant d’un nœud coïncident avec l’ordre <x. L’ensemble X est totalement ordonné, on appelle <x cette relation d’ordre.

106 Implémentation Java Key Mapping :
Chap. 4. : Type de données abstrait Implémentation Remarque : une représentation d’une collection par un arbre lexicographique correspond à un mapping! Java Key Mapping : new() operator : crée un objet de type map et retourne un mapping vide; get(e) operator : retourne la valeur associée à la clé e si cette clé existe, nil dans le cas contraire; put(e,value) operator : insère la clé e dans le map et lui associe la valeur value. Dans notre cas l’ensemble des clés corresponds à l’ensemble des sous-ensembles et les valeurs associées peut être un booléen correspondant à la présence de la clé dans la collection.

107 Comparaison d’implémentation
Chap. 4. : Type de données abstrait Comparaison d’implémentation En Java un mapping est implémenté par des tables de Hachage. Plusieurs implémentations différentes d’un arbre lexicographique peuvent être proposées en fonction de la façon dont l’ensemble des fils sont représenté : Par un tableau; Par des listes chaînées; Ici les résultats sont variables; d’une façon générale si la collection est de taille très importante l’arbre est beaucoup plus efficace sur l’ensemble des opérations. Dans un cas de petite collection la table de hachage est très efficace; Dans les cas intermédiaires l’utilisation de listes chaînées est plus efficace en moyenne que les tables de hachage.

108 T.D.A. Gestion de partition
Chap. 4. : Type de données abstrait T.D.A. Gestion de partition Définition : Une partition p d’un ensemble e est un ensemble de parties non vides de e, deux à deux disjointes et dont la réunion est égale à e. Opérations : p.trouverClasse(e) : retourne la classe de e dans p; p.union(c1,c2) : fusionne les deux classes c1 et c2 dans p; En général, on part d’une partition où chaque classe est réduite à un singleton, puis on traite une suite de requêtes de l’un des deux types ci-dessus.

109 Gestion de partition : Implémentation
Chap. 4. : Type de données abstrait Gestion de partition : Implémentation 1 2 3 4 1 2 3 4 5 6 7 8 9 10 11 Partition : { {0,1,5,9}, {2,6,10}, {3,7,8,11}, {4} } Fusion en O(n) Recherche en O(1) Question : Quelle est la complexité des opérations de fusion et de recherche?

110 Gestion de partition : Implémentation
Chap. 4. : Type de données abstrait Gestion de partition : Implémentation 2 3 4 1 5 11 6 10 7 9 8 Partition : { {0,1,5,9}, {2,6,10}, {3,7,8,11}, {4} } On choisi un représentant dans chaque classe, ainsi la fusion revient à changer le représentant pour la classe fusionnée. On peut alors représenter cette partition par une forêt, c’est à dire par une simple relation père. On peut alors utiliser un tableau pour représenter cette forêt. 2 3 4 7 5 Père : 1 2 3 4 5 6 7 8 9 10 11

111 Gestion de partition : Implémentation
Chap. 4. : Type de données abstrait Gestion de partition : Implémentation 3 2 4 1 5 7 11 6 10 8 9 Question : Quelle est la complexité des opérations de fusion et de recherche avec une implémentation par un tableau « Père »? Fusion en O(1) si on dispose des racines sinon il faut les rechercher en O(h) Recherche en O(h). Quelle amélioration pourrions nous apporter pour réduire la complexité théorique de l’opération de recherche?

112 Chap. 4. : Type de données abstrait
Pour résumer Nous avons défini un T.D.A. comme un ensemble d’objets cohérent muni d’opérations données. Nous avons dit que l’implémentation d’un T.D.A. devait respecter des contraintes d’efficacité (en espace et en temps). Nous avons défini les T.D.A. : ensemble dynamique, dictionnaire, pile, file, file de priorité, collection, gestion de partition. L’implémentation de chacun de ces T.D.A. repose sur des structures de données évoquées au chapitre précédent : liste, tableau, arbre, tas, arbre binaire de recherche.

113 Université Blaise Pascal
Chapitre 5 Table de hachage Olivier Raynaud Université Blaise Pascal

114 Chap. 5 : Table de hachage Principe Définition : Une table de hachage est une structure de données permettant d’implémenter le T.D.A. Dictionnaire. Une table de hachage généralise la notion de tableau. T Clefs possibles : U Clefs réelles : K On notera par m la taille du tableau ou table de hachage, par n le nombre de clefs réellement stockées, U l’univers des clefs possibles et K l’ensemble des clefs réelles. T est le nom de la table. En général on utilise un tableau dont la taille est proportionnelle au nombre de clefs réellement stockées. Bien sur la complexité des opérations est dans le pire des cas en O(n) mais nous verrons qu’avec des hypothèses raisonnables, le temps moyen de recherche est en O(1). Exemple : un compilateur de langage de programmation doit tenir à jour une table des symboles dans laquelle les clés des éléments sont des chaînes de caractères arbitraires qui correspondent aux identificateurs du langage.

115 Table à adressage direct
Chap. 5 : Table de hachage Table à adressage direct Technique adaptée au cas où la taille de U est petite T 1 : … Nil 6 6 : … Dans le cas de l’adressage direct deux éléments ne peuvent pas partager la même clef. Dans la table à adressage direct chaque position ou alvéole correspond à un élément de l’ensemble ayant pour clef k. Il s’agit ici de la notion de tableau caractéristique. L’implémentation des opérations du dictionnaire est triviale : t.rechercher(x) : retourner t[cle(x)]; t.insérer(x) : t[cle(x)] <- x; retouner t; t.supprimer(x) : t[cle(x)] <- Nil; retourner t; Dans certain cas, plutôt que la table stocke des pointeurs vers des objets on préférera directement stocker les objets dans la table. 8 1 8 : …

116 Chap. 5 : Table de hachage Table de hachage Définition : On utilise une fonction de hachage « h » pour calculer l’adresse de l’alvéole à partir de la clef k. h établit une correspondance entre l’univers U des clefs et les alvéoles de la table de hachage T h(k1) Clefs possibles : U h(k2)=h(k4) k1 Les Inconvénients d’une table à adressage direct sont évidents : gaspillage d’espace ou impossibilité technique de disposer d’un tableau dont la taille correspond à la taille de l’univers possible des clefs. La table de hachage va nous permettre de réduire le besoin d’espace à O(K). Le temps moyen d’accès sera en O(1). Ce qui correspond à la valeur dans le pire des cas pour une table à adressage direct. Vocabulaire : on dit qu’un élément de clé k est haché dans l’alvéole h(k), on dira aussi que h(k) est la valeur de hachage de la clef k. Ainsi au lieu de U valeurs il suffit de gérer m valeurs. Les besoins de stockage sont réduits en conséquence. « Le problème est que deux clefs peuvent être hachées dans la même alvéole. Ce qu’on appelle une collision. Heureusement il existe des techniques efficaces de résolution de conflits crées par les collisions. » Remarquons que la fonction h doit être déterministe. « Le terme haché évoque une découpe désordonnée en petits morceaux. En rendant h un peu aléatoire on peut se protéger d’un nombre de collisions trop élevé », d’où le terme hachage. Il faut donc trouver une fonction de hachage qui minimise le nombre de collisions. k2 k4 k3 h(k3) Fonction de hachage h

117 Résolution par chaînage
Chap. 5 : Table de hachage Résolution par chaînage T k1 Clefs possibles : U k2 -> k4 k1 k2 k4 k3 k3 Fonction de hachage h α = n/m Implémentation : t.insérer(x): insérer x en tête de liste T[h(cle(x))]; en O(1); t.rechercher(x) : recherche un élément x dans la liste T[h(cle(x))]; complexité dans la taille de la liste. t.supprimer(x) : supprimer x de la liste T[h(cle(x))]; complexité dans la taille de la liste. Sous l’hypothèse du hachage uniforme simple : chaque élément à la même chance d’être haché dans n’importe quelle alvéole, indépendamment du hachage des éléments précédents. On appelle α le facteur de remplissage, c’est-à-dire le nombre moyen d’éléments stockés dans une chaîne. Analyse en moyenne : O(1+ α); en effet : Temps de calcul de h(k) en O(1), longueur de chaque liste chaînée : n * 1/m = α. De plus, si la taille de n est proportionnelle à celle de m, la valeur α devient une constante et la complexité de chaque opération en moyenne devient constante. Ici on peut proposer un exemple extrait du Cormen : insérer dans une table de hachage de taille 9 la série d’éléments 5,28,19,15,20,33,12,17,10. La fonction de hachage étant h(k)=k mod 9. Hypothèse du hachage uniforme simple : chaque clef a autant de chance d’être hachée dans l’une quelconque des m alvéoles.

118 Construction Σ P(k) = 1 / m
Chap. 5 : Table de hachage Construction Remarque : Une bonne fonction de hachage vérifie l’hypothèse de hachage uniforme simple. Σ P(k) = 1 / m Soit j ∈ [1,m] k:h(k)=j La difficulté réside dans la construction d’une fonction de hachage qui vérifie l’hypothèse. Expliquer l’équation : On suppose que chaque clé est tirée aléatoirement et indépendamment de U selon une loi de probabilité P. Ainsi P(k) est la probabilité que k soit tirée. Si on prend tous les k tels que h(k)=j, la somme de leur probabilité d’apparition doit être exactement égale à 1/m. Malheureusement dans la majorité des cas cette loi de probabilité n’est pas connue. C’est très important car l’efficacité de la structure dépend très largement du comportement probabiliste des clés à hacher. On peut ici donner un exemple de bonne fonction de hachage : supposons que les clefs soient des nombres réels aléatoires, répartis indépendamment et uniformément dans l’intervalle 0<k<1. On peut montrer que la fonction de hachage h(k)=PEI(km) vérifie l’équation donnée. Dans la suite nous allons proposer différentes fonctions de hachage et nous supposerons que clefs sont des entiers naturels. Méthode par division : h(k)=k mod m Il faut donc choisir m et faire en sorte que la fonction de hachage dépende de tous les bits de la clé. Idée : on fixe α = n/m et on prend m comme nombre premier éloigné d’une puissance exacte de deux immédiate.

119 Chap. 5 : Table de hachage Méthode la division Définition : La méthode de la division fait correspondre une clé k avec l’une des m alvéoles en prenant le reste de la division de k par m. Autrement dit : h(k) = k mod m [CLR90] Ce hachage ne demande qu’une division. Question : Comment choisir m? A titre d’exemple m=12, k=100 et h(k)=4. Question : Comment choisir m? Attention au choix de m. Par exemple m ne doit pas être une puissance de 2 . Sinon pour m=2^p, nous avons identité entre les p premiers bits de k et h(k). Le calcul de la clé ne dépend plus alors que d’une partie de k et non pas k tout entier. Le même raisonnement peut se faire avec n=100, m=10 et h(k)=k mod 10. Le résultat ne dépend plus du nombre initial mais uniquement de son nombre d’unité. Pourquoi premier? Par exemple : nous voulons stocker 2000 chaînes de caractères, 3 collisions nous semblent acceptable. On choisit m=701 car 2000/3 est proche de 701, 701 est premier et loin de toute puissance de 2.

120 Chap. 5 : Table de hachage Hachage universel Définition : Soit H une collection finie de fonctions de hachage de U dans {0,1,…,m-1}. H est Universelle si pour tout (x,y) de U, le nombre de fonctions telles que h(x)=h(y) vaut |H|/m. [CLR90] Le principe consiste à choisir aléatoirement dans H une fonction de hachage à chaque exécution. L’algorithme peut donc avoir un comportement différent pour un ensemble de clés identiques. Le hachage universel est proposé pour éviter les comportements dans le pire des cas (ou la technique du fourbe) des fonctions de hachage données précédemment. Pour assurer un comportement moyen de hachage on s’appuiera sur une collection construite aléatoirement de fonctions. Une clé est alors hachée par l’une des fonctions de la collection choisie aléatoirement. Autrement dit, avec une fonction de hachage h choisie aléatoirement dans H, les chances de collision de x et y distincts sont exactement 1/m, ce qui représente précisément les chances de collision si h(x) et h(y) sont choisies aléatoirement dans {0,1,…,m-1}. m est pris premier. Avec n<=m on montre que l’espérance d’une collision E[cyz]=1/m et que E[Cx]=(n-1)/m.

121 Hachage universel ha(x) = Σ ai . xi (mod m)
Chap. 5 : Table de hachage Hachage universel Définition : Soit la collection H définie comme suit : ha(x) = Σ ai . xi (mod m) Avec a=<a0,a1,…,ar> pour tout ai dans {0,1,…,m-1} et x=<x0,x1,…,x r> r i=0 [CLR90] Les « ai » sont choisis aléatoirement avant l’exécution et définissent donc la fonction de hachage ha à appliquer à l’ensemble des clés. Une clé est décomposée en r+1 octets. Montrons que H = ⋃a {ha} est une classe universelle de fonctions de hachage. Soient x et y un couple de clé distinctes. Supposons que x0 soit différent de y0, alors il existe un unique a0 qui vérifie l’équation h(x)=h(y). Cet a0 est solution de l’équation : a0(x0-y0) = - Σ ai (xi-yi) (mod m). Cette équation est de la forme x.a = b (mod m). Nous savons que cette équation admet d solutions avec d=pgcd(a,m). Dans le cadre de notre équation, en choisissant m premier, a0 devient unique. Ainsi x et y entre en collision pour exactement mr valeurs de a. Et comme mr = |H|/m, H est Universelle. De plus comme il y’a mr+1 valeurs possibles pour a, la probabilité de collision est mr/mr+1=1/m. H = ⋃ {ha} est une classe universelle de fonctions de hachage a

122 Adressage ouvert Définition : On dit d’une table de hachage qu’elle
Chap. 5 : Table de hachage Adressage ouvert Définition : On dit d’une table de hachage qu’elle réalise un adressage ouvert si tous les éléments sont stockés dans la table elle-même. [CLR90] Pour rechercher ou insérer un élément dans la table on calcule une séquence d’alvéoles suivant un schéma préétabli. L’élément est inséré dans la première alvéole libre de cette séquence. En adressage ouvert on proscrit les pointeurs, les listes. Ainsi une cellule de la table de hachage contient soit un élément soit un pointeur nil. La mémoire gagnée par économie de pointeurs est utilisée pour agrandir la table. La séquence des positions dépend de la clé à insérer. On parle d’adressage ouvert parce que la position (l’alvéole) finale d’une clé donnée n’est pas connue à l’avance. Elle dépend de ce qui est déjà stocké dans la table de hachage.

123 Numéro de sondage Définition : Une fonction de hachage en « adressage
Chap. 5 : Table de hachage Numéro de sondage Définition : Une fonction de hachage en « adressage ouvert » impose comme second paramètre un numéro de sondage : h : U x {0,1,…,m-1}  {0,1,…,m-1} De plus, pour chaque clé k la séquence <h(k,0), h(k,1),…, h(k,m-1)> doit réaliser une permutation de l’ensemble {0,1,…,m-1}. Algorithme tH.inserer() Données : k:entier; Résultat : numero : entier (le numéro de l’alvéole dans laquelle k est inseré); Début i  0; j  h(k,i); Tantque (t[j] != nil et i<=m) faire i  i +1; FinTq si (t[j]=nil) alors t[j]  k; retourner k; sinon retourner m; Fin Algorithme tH.rechercher() Résultat : numero : entier (le numéro de l’alvéole dans laquelle k est inserer); si (t[j]=nil) alors retourner k; La suppression pose un problème. En effet si on met simplement nil, la recherche d’une clé n’est alors plus cohérente. «Une solution est alors de marquer l’alvéole en y stockant la valeur Oté au lieu de nil. Il faut changer le code de l’insertion et insérer dans les cases marquées ôter; Par contre la fonction de recherche change très peu. Une conséquence est que la complexité des opérations de recherche ne dépend plus du facteur de remplissage.

124 Hachage uniforme Définition : l’hypothèse de hachage uniforme suppose
Chap. 5 : Table de hachage Hachage uniforme Définition : l’hypothèse de hachage uniforme suppose que chacune des m! permutations possibles de l’ensemble {0,1,…,m-1} a autant de chance de constituer la séquence de sondage de chaque clé. On applique des approximations : Sondage linéaire; Sondage quadratique; Sondage par double hachage. Il s’agit d’une généralisation de la notion de hachage uniforme simple pour laquelle la fonction produit une séquence de sondage complète. En pratique le hachage uniforme est très difficile à mettre en place. Les trois approximations proposées garantissent que la séquence <h(k,0), h(k,1),…,h(k,m-1)> soit une permutation de l’ensemble {0,1,…,m-1} pour chaque clé k. Mais elles ne vérifient pas l’hypothèse de hachage uniforme.

125 Sondage linéaire Définition : soit h’ : U  {0,1,…,m-1}, le sondage
Chap. 5 : Table de hachage Sondage linéaire Définition : soit h’ : U  {0,1,…,m-1}, le sondage linéaire utilise la fonction de hachage : h(k,i) = ( h’(k) + i ) mod m (i ∈ [0,m-1]) Analyse : le sondage linéaire n’utilise que m séquences de sondage distinctes; le sondage linéaire génère des grappes à l’intérieur de la table de hachage. La première alvéole sondée est t[h’(k)], jusqu’à t[m-1], puis sont testées les alvéoles t[1], t[2], pour finir à t[h’(k)-1]. L’inconvénient majeur de cette technique est la génération de grappes dans la table. De longues suites d’alvéoles sont ainsi remplies augmentant le temps de recherche moyen. Pourquoi : soit une alvéole m vide, précédée de i alvéoles pleines, la probabilité que m soit la prochaine est de (i+1)/m tandis que si la précédente est vide la probabilité est de 1/m.

126 Sondage quadratique Définition : soit h’ : U  {0,1,…,m-1}, le sondage
Chap. 5 : Table de hachage Sondage quadratique Définition : soit h’ : U  {0,1,…,m-1}, le sondage quadratique utilise la fonction de hachage : h(k,i) = ( h’(k) + c1 i + c2 i2 ) mod m (i ∈ [0,m-1]) Analyse : le sondage quadratique n’utilise que m séquences de sondage distinctes; le sondage quadratique génère des grappes faibles. La première position sondée est t’(h(k)), les positions suivantes sont à des distances qui dépendent du carré du nombre de sondages i. Pour un bon comportement il faudra choisir avec diligence les constances c1, c2 et m. Le sondage quadratique n’utilise que m séquences de sondage distinctes : puisque le premier sondage détermine toute la séquence, on a que m séquences possibles de sondage. Le sondage quadratique génère des grappes faibles : si deux clés ont la même première position, toute la séquence sera identique d’où la naissance de grappes faibles. En effet si h(k1,0)=h(k2,0), alors pour tout i on a h(k1,i)=h(k2,i), Pour utiliser correctement toute la table il faut choisir avec attention les valeurs m, c1 et c2.

127 Sondage par double hachage
Chap. 5 : Table de hachage Sondage par double hachage Définition : soit h1, h2 : U  {0,1,…,m-1} deux fonctions de hachage, la technique du sondage par double hachage utilise la fonction : h(k,i) = ( h1(k) + i h2(k) ) mod m (i ∈ [0,m-1]) Analyse : le sondage par double hachage utilise m2 séquences de sondage distinctes; La première position est t[h1(k)]; « les positions suivantes sont des déplacements à partir de la position précédente, de quantité h2(k) », le tout modulo m. Ainsi, h2(k) doit être premier avec m sinon on boucle sur quelques adresses de la table de hachage. En effet si m et h2(k) admettent un plus grand diviseur d pour une clé k, la recherche de k ne teste que 1/d ième de la table. Exemple avec h2(k)=10, m=15 et donc d=5. Conseil : prendre m puissance de 2, et h2(k) produisant toujours un nombre impair, on aura alors quelque soit k, d=1. Prendre m premier et h2(k) toujours positif et inférieur à m. Ex: h1(k)=k mod m; h2(k)=1+(k mod m’) le sondage par double hachage utilise m2 séquences de sondage distinctes : en effet chaque paires (h1(k),h2(k)) possible engendre une séquence de sondage distincte. Ainsi les performances du sondage par double hachage semblent plus proches de celle du schéma «idéal» du hachage uniforme. Exemple : considérons la table 0,79,0,0,69,98,0,72,0,0,0,50,0; avec comme fonction de hachage h1(k)=k mod 13, et h2(k)=1 + k mod 11 Insérons le nombre 14 : on sondera les alvéoles 1, 5, et est insérédans l’alvéole 9.

128 Pour résumer Gestion des collisions :
Chap. 5 : Table de hachage Pour résumer Une table de hachage implémente le T.D.A. Dictionnaires et se présente comme une généralisation d’un tableau caractéristique. A un couple (objet, clé) correspond une alvéole dans la table de hachage. Gestion des collisions : Par chaînage; Par adressage ouvert; (sondage linéaire, quadratique et par double hachage)

129 Université Blaise Pascal
Chapitre 6 Complexité Olivier Raynaud Université Blaise Pascal

130 Qu’est-ce qu’un problème?
Chap. 6 : Complexité Qu’est-ce qu’un problème? Problème : Quelle est la valeur, après un an, d’une somme d’argent placée à un taux d’intérêt simple. Un problème est une question générale qui attend une réponse. Il est composé de paramètres et de variables libres laissées non renseignées. Une instance du problème est une expression du problème pour laquelle les paramètres ont été fixés.

131 Chap. 6 : Complexité Un algorithme Définition : Un algorithme est une procédure finie, pas à pas, qui prend en entrée une instance d’un problème et calcule la solution correspondante. On dit d’un algorithme qu’il résout un problème donné si cet algorithme appliqué à une instance quelconque du problème garantit toujours de produire une solution pour cette instance.

132 Evaluation d’algorithmes
Chap. 6 : Complexité Evaluation d’algorithmes Question : étant donnés deux algorithmes qui calculent les solutions à un même problème. Comment comparer ces algorithmes? Autrement dit, quel est le meilleur? Intuition : On préférera celui qui nécessite le moins de ressources : Ressource de calculs; Ressource d’espace de stockage; Dans la suite de ce chapitre on s’intéressera à l’évaluation des temps de calculs d’un algorithme.

133 Evaluation des temps d’exécution
Chap. 6 : Complexité Evaluation des temps d’exécution Problématique : Comment évaluer le temps d’exécution d’un algorithme donné? Idée : compter le nombre d’opérations élémentaires effectuées lors de l’exécution. Idée : compter le nombre d’opérations élémentaires effectuées lors de l’exécution : le problème est que ce nombre d’opérations varie avec les données d’entrée de l’algorithme.

134 Opération élémentaire
Chap. 6 : Complexité Opération élémentaire Définition : Une opération élémentaire est une opération qui s’effectue en temps constant sur tous les calculateurs usuels. On considérera les opérations suivantes comme élémentaires (sur des types simples): Comparaisons; Opérations arithmétiques et logiques; Entrée-sortie; Ainsi une opération élémentaire est une opération dont le temps d’exécution est bornée par une constante indépendante de l’implémentation et de la taille de la donnée. Remarques : ces opérations sont élémentaires uniquement dans le cas de variables de type simple (atomique). Dans le cas de variable de type composé (tableau, chaîne, liste, ensemble), ces opérations ne sont plus élémentaires. Un calculateur usuel : un opérateur, un boulier, un PC (cf. support de Eric). « Une opération qui se compose de plusieurs opérations élémentaires peut être considérée comme une OE si le nombre d’OE qui la compose est constant « (ex: échange du contenu de deux variables). Par contre le nombre d’OE qui compose une opération de lecture d’un mot (de plusieurs caractères) dépend de la longueur du mot. De la même façon le nombre d’OE qui composent la fonction puissance dépend naturellement du nombre de multiplication à exécuter (Cf. support d’Eric).

135 Fonction de complexité
Chap. 6 : Complexité Fonction de complexité Définition : La fonction de complexité temporelle d’un algorithme exprime le temps requis, par l’algorithme, pour calculer la solution correspondant à une instance en fonction de la taille de celle-ci. Cette fonction de complexité dépend donc du codage retenu pour évaluer la taille de l’instance et du modèle de machine utilisé pour l’évaluation du temps d’exécution d’une opération élémentaire.

136 Hypothèses de simplification
Chap. 6 : Complexité Hypothèses de simplification Pour évaluer le nombres d’opérations élémentaires on s’appuie sur les paramètres de description de la donnée. nombre d’éléments d’un tableau; nombre de caractères d’une chaîne; nombre d’éléments d’un ensemble; profondeur et largeur d’un arbre; nombre de sommets et d’arêtes d’un graphe; dimension d’une relation d’ordre; taille ou valeur des nombres caractéristiques du problème;

137 Critères d’évaluation
Chap. 6 : Complexité Critères d’évaluation Pour une même taille de donnée, le nombre d’opérations élémentaires exécutées reste variable. On propose alors plusieurs critères d’évaluation : Analyse dans le pire des cas : t(n) = maximum des temps d’exécution de l’algorithme pour toutes les instances de taille n. Analyse moyenne : tmoy(n) = moyenne des temps d’exécution de l’algorithme pour toutes les instances de taille n. L’analyse en moyenne reste délicate à mettre en œuvre car elle nécessite d’avoir une bonne connaissance par avance des instances qui seront présentées à l’algorithme. Elle dépend ainsi fortement du contexte d’utilisation. Les outils d’évaluation sont aussi très techniques (mathématiques probabilistes et statistiques). Pour ces différentes raisons on préférera l’analyse dans le pire des cas.

138 Chap. 6 : Complexité Ordre de grandeur Il reste fastidieux de compter toutes les opérations élémentaires d’une exécution. Ordre de grandeur : On dit qu’une fonction f(n) est en O(g(n)) s’il existe une constance c, positive et non nulle, telle que |f(n)| ≤ c |g(n)| n ≥ 0 3 n + 15 est en O(n); n² + n est en O(n²); 2 n + n log2 n est en O(n log n); log2 n + 25 est en O(log2 n); Ce qui est vraiment intéressant, c’est le comportement de la fonction de complexité pour les grandes valeurs de n. On parle alors de comportement à la limite ou d’ordre de grandeur de la fonction f. Les règles de composition sous jacentes sont : Si t1(n) est en O(f(n)) et t2(n) est en O(g(n)) alors t1(n)+t2(n) est en O(Max(f(n),g(n))) et t1(n).t2(n) est en O(f(n).g(n)).

139 Exercices Question 1 : évaluer les poids relatifs de chacun
Chap. 6 : Complexité Exercices Question 1 : évaluer les poids relatifs de chacun des termes du polynôme 3x² + 10x + 5. Question 2 : évaluer les poids relatifs de chacun des termes de la fonction de complexité kxn + λkx. On donne une valeur pour x, par exemple 20 et on évalue le poids de chacun des termes par rapport à la valeur totale du polynôme.

140 Ordre de grandeur Tâche Complexité Chap. 6 : Complexité O(1) O(log n)
Accès direct à un élément O(log n) Divisions successives par deux d’un ensemble O(n) Parcours d’un ensemble O(n log n) Divisions successives par deux et parcours de toutes les parties O(n²) Parcours d’une matrice carrée de taille n O(2n) Génération des parties d’un ensemble O(n!) Génération des permutations d’un ensemble

141 Ordre de grandeur Question : quelle peut être l’influence du codage et
Chap. 6 : Complexité Ordre de grandeur Question : quelle peut être l’influence du codage et du modèle de machine pour l’évaluation de la complexité d’un algorithme? La taille du codage choisie diffère au plus polynomialement si l’on respectes les deux conditions suivantes: Le codage d’une instance doit être concis et ne pas comporter d’information non nécessaire. Les nombres apparaissant dans la description de I ne doivent pas être représentés en base unaire.

142 Exemple de codage Extrait de [GJ00] 10 5 9 6 3 9 C1 C2 C3 C4
Chap. 6 : Complexité Exemple de codage Extrait de [GJ00] 10 C1 5 9 C2 6 C3 3 9 C4 L’alphabet peut être : {c,[,],/,0,1,2,3,4,5,6,7,8,9} Et le codage obtenu : « c[1]c[2]c[3]c[4]//10/5/9//6/9//3 » Si n est le nombre de sommets et m la valuation maximale on obtient une taille de codage de : n * (3 + log n) + 2n. + log m +2 ??? A refaire.

143 Comparaison de codage S1 S2 S3 S4 Soit G=(S,A) avec s=|S| et a=|A|
Chap. 6 : Complexité Comparaison de codage S1 S2 S3 S4 Liste de sommets et liste d’arêtes : s1s2s3s4(s1s2)(s1s4)(s3s4) = Borne inf : 2s + 6a Borne sup : 2s+10a+(s+2a)log10(s) Liste de voisins : (s2s4)(s1)(s4)(s1s3) = Borne inf : 2s + 4a Borne sup : 2s+4a+ 2a.log10(s) (on a s listes et donc 2s parenthèses et chaque arêtes va coûter 2*2=4, en effet chaque extrémité (de taille 2 comme s1 par exemple) sera présente dans une des listes) Matrice d’adjacence : 0101/1000/0001/1010 = Borne inf : s²+s Borne sup : s²+s-1 Remarque : la borne supérieure correspond au cas où le nombre de sommet dépasse 10. Il faut alors coder chaque sommet avec un nombre de chiffre égal à log(s) en base 10. Puisque a est de l’ordre de s² ceci montre que la longueur des données d’entrée ne diffère pas plus d’un facteur polynomial. Soit G=(S,A) avec s=|S| et a=|A| Comparer la taille des codages de G en fonction de sa représentation.

144 Impact du modèle de machine
Chap. 6 : Complexité Impact du modèle de machine Machine simulant 1TM kTM RAM O(T(n)) O(T(n)logT(n)) O(T²(n)) O(T3(n)) Machine simulée 1TM : une machine de Turing à un ruban kTP : machine de Turing à k rubans RAM : Random access machine Comment lire ce tableau ? Temps requis par la machine A (simulante) pour simuler l’exécution d’un algorithme de complexité temporelle T(n) sur une machine B (simulée). Soit la fonction de complexité T(n) d’un algorithme s’exécutant sur une machine 1TM pour simuler une machine 1TM, la fonction de complexité restera la même sur une machine kTM et passera à T(n)Log(n) sur une machine RAM (toujours pour similer 1TM). On renvoi ici aux travaux de Hopcroft et Ullman des années 70. Extrait de [GJ00]

145 Algorithme polynomial
Chap. 6 : Complexité Algorithme polynomial Définition : Un algorithme polynomial est un algorithme dont la complexité est en O(p(n)) avec p une fonction polynomiale quelconque. Autrement dit si A est un algorithme et f(n) sa fonction de complexité, A est polynomial si et seulement si il existe un polynôme p tel que f(n) est en O(p(n)).

146 Algorithme exponentiel
Chap. 6 : Complexité Algorithme exponentiel Définition : Un algorithme est en temps exponentiel si et seulement si il n’est pas polynomial. Cette définition par exclusion à l’inconvénient de classer exponentielle une fonction telle que nlog(n) qui ne l’est pas pour certains. Définition : Un problème est dit intraitable s’il est si difficile qu’aucun algorithme polynomial puisse le résoudre. A noter ici que l’on parle pour la première fois du lien entre la complexité des algorithmes et celle des problèmes. Attention il s’agit de définition formelle concernant le cas général. La complexité en temps est mesurée dans le pire des cas et si l’on dit d’un algorithme qu’il est exponentiel nous disons en fait qu’il existe une instance de taille n qui requiert ce temps là. Pour certains problème bien connus il existe de nombreuses instances qui requièrent peu de temps : L’algorithme du simplex détient des records de rapidité alors qu’il est exponentiel. La technique Branch and bound pour le sac à dos est efficace alors que la complexité théorique est exponentielle. Ces exemples peuvent laisser penser que les techniques employées captures des propriétés internes aux instances et qu’il existerait donc des algorithmes polynomiaux qui utiliserait ces propriétés.

147 Temps d’exécution Extrait de [GJ00] 10 20 30 40 50 60 n n² n3 n5 2n 3n
Chap. 6 : Complexité Extrait de [GJ00] Temps d’exécution fonction 10 20 30 40 50 60 n .00001s .00002s .00003s .00004s .00005s .00006s .0001s .0004s .0009s .0016s .0025 .0036s n3 .001s .008s .027s .064s .125s .216s n5 .1s 3.2s 24.3s 1.7mn 5.2mn 13.0mn 2n 1.0s 17.9mn 12.7j 35.7an 366siè 3n .059s 58 mn 6.5 an 3855siè 2 108siè siè Hypothèse de ce tableau : une instruction toute les 10-6 seconde. Ce qui distingue aussi les deux classes de problèmes est la possibilité de prévoir à l’avance le temps d’exécution. Aucune technique n’existe pour les algorithmes exponentiels. Alors que l’on peut le faire pour les algorithmes polynomiaux. Enfin l’expérience montre que la plupart des algorithmes polynomiaux sont en O(n2) ou O(n3) avec des constances raisonnables. C’est aussi une raison essentielles de choisir de résoudre des problèmes avec ces algorithmes. En pratique des algorithmes en O(n100) ou O(1099 n²) ne sont pas efficaces.

148 Projection Extrait de [GJ00] 1 100 1000 n n² n3 n5 2n 3n fonction
Chap. 6 : Complexité Extrait de [GJ00] Projection fonction 1 100 1000 n N1 100N1 1000N1 N2 10N2 31.6N2 n3 N3 4.63N3 10N3 n5 N4 2.5N4 3.98N4 2n N5 N5+6.64 N5+9.97 3n N6 N6+4.19 N6+6.29 Ce tableau montre comment l’instance la plus grande traitable en une heure par un algorithme évoluera si l’on dispose d’une machine 100 fois et 1000 fois plus puissante. On peut en particulier comparer le comportement pour les fonction n5 et 2n. Pour cette raison un algorithme exponentiel (non polynomial) peut être considérer comme un mauvais algorithme. Autrement dit on peut affirmer qu’un problème est bien compris, bien résolu si on dispose d’un algorithme polynomial pour le résoudre.

149 Pour aller plus loin Question : Que faire fasse à un problème
Chap. 6 : Complexité Pour aller plus loin Question : Que faire fasse à un problème intraitable? Proposer une solution algorithmique qui calcule une valeur approchée de la solution optimale. (Méthode heuristique telle que le recuit simulé, la méthode tabou, les algorithmes génétiques…) En fait ces méthodes trouvent des applications industrielle importantes (cf. cours de Gourgand et Quillot).

150 Pour aller plus loin Question : A quelle classe de complexité
Chap. 6 : Complexité Pour aller plus loin Question : A quelle classe de complexité appartient un problème donné? Une des problématiques majeures de l’informatique théorique concerne le classement des problèmes. Un problème donné est-il traitable ou intraitable? S’il est intraitable existe-t-il de bons algorithmes d’approximation? On peut montrer par exemple que certains problèmes intraitables ne peuvent pas être approximés au dessous d’un facteur donné.

151 Chap. 6 : Complexité Pour résumer Une des problématiques majeures de l’informatique théorique concerne le classement des problèmes. Un problème donné est-il traitable ou intraitable? S’il est intraitable existe-t-il de bons algorithmes d’approximation? On peut montrer par exemple que certains problèmes intraitables ne peuvent pas être approximés au dessous d’un facteur donné.

152 Université Blaise Pascal
Chapitre 7 Applications Olivier Raynaud Université Blaise Pascal

153 Applications 2 étude de cas :
Chap. 7 : Application Applications 2 étude de cas : Compression avec l’algorithme de Huffman; Recherche dans un nuage de points;

154 Compression de données
Chap. 7 : Application Compression de données Le fait de comprimer les informations touche principalement deux domaines d ’application : le stockage des informations; le transfert sur une ligne de communication. Le stockage : En supposant disposé d ’une technique de compression de quotient de compression de 2 on peut doublé la capacité de stockage de tous les support habituel. Cela fait gagne de l ’argent, on achète des disques dont la taille suffit. De plus cela fait gagner de temps, puisque l ’on diminue par 2 le nombre d accès disque pour lire l intégralité de l information. La communication : Il y ’a 2 aspect importants. Avec la même méthode de compression nous pouvons doublé par 2 la vitesse de transmission des données d ’ou un gain de temps particulièrement important. Par contre en adaptant votre stratégie en fonction de vos besoins vous préféreriez peut être diminuer vos coût de liaison, pour cela acheter des modems moins efficace et donc moins chers et grâce a votre algorithme conservé les performance d ’avant.

155 Évaluation de la compression
Chap. 7 : Application Évaluation de la compression Définition : Le quotient de compression est le degré de réduction des données et est égal au quotient : Taille Originale / Taille compressé. Définition : Le taux de compression exprime en pourcentage l’inverse du quotient de compression: taux de compression = 1 / quotient de compression On obtient un gain de compression (exprimé en pourcentage) = 1 - taux de compression Exemple : 40 caractère de données originales en 10 caractères de données compressée a un quotient de 4, un taux de 25 pour cent et un gain de 75 pour cent. Les premières méthodes de compression de données avaient pour objectif de supprimer les blancs lors de communication (chez IBM) On obtenait des gain de 30 à 50 pour cent.

156 Chap. 7 : Application Question Contexte : Les méthodes actuelles pour compresser du texte admettent des taux de compression de 50%, pour des images statiques le taux est de 80% et pour des images de films le gain est de l’ordre de 95%. Question : Les méthodes utilisées dans ces trois cas admettent telles les mêmes contraintes? On distingue en effet la compression sans perte, où les données compressées sont identiques aux données décompressées (compression de textes, de données scientifiques ou de code compilé de programmes). Par contre pour la compression de l’image et du son, une perte peut être acceptée si elle n’est pas perceptible ou si elle est corrigée automatiquement par le percepteur.

157 Chap. 7 : Application Les méthodes Actuellement on distingue plusieurs grandes catégories d ’algorithmes de compression sans perte : Ceux qui compressent les répétitions; Ceux qui s ’appuient sur des méthodes de codage statistiques; Ceux qui font intervenir des dictionnaires; Ceux à caractère prédictif . Ceux qui compressent les répétitions Il s ’agit du Run Lenght Encoding qui généralise la compression de blancs. Ceux qui s ’appuient sur des méthode de codage statistiques On y trouve l ’algorithme de Huffman et de Shannon/Fano Ceux qui font intervenir des dictionnaires C ’est la méthode de Lempel Ziv Welch partent du principe que des chaînes apparaissent régulièrement dans les données sources peuvent être remplacées par un indice représentant leur adresse dans un dictionnaire de référence construit progressivement. Ceux à caractère prédictif Ils cherchent à prévoir les caractères futurs en fonction des caractères déjà lus.

158 Chap. 7 : Application Code préfixe Définition : Un ensemble P de mots non vides est un code préfixe si aucun des mots de P n’est préfixe propre d’un autre mot de P. Exemple : {0,100,101,1100,1101} 1 R 1 Ainsi nous avons la proposition suivante : Proposition : un ensemble fini de mots sur {0,1} est un code préfixe si et seulement si il est le code des feuilles d’un arbre binaire. Ce code de l’exemple est préfixe, il n’y aura donc pas ambiguïté lors du décodage, malheureusement il n’est pas complet donc certaines séquence ne pourront pas être décodées. Exemple : la séquence est censée donner ABRACADABRA avec 31 bits. Pas d’ambiguïté. Par contre toute séquence ne correspond pas forcément à un mot Par exemple etc on trouve : R D et 111 reste introuvable. 1 1 C D B A

159 Code préfixe complet R F C D B A
Chap. 7 : Application Code préfixe complet Définition : Un ensemble P de mots non vides est un code préfixe complet si tout mot est préfixe d’un produit de mots de P. Exemple : {0,100,101,111,1100,1101} 1 R 1 Ainsi nous avons la proposition suivante : Proposition : un ensemble fini de mots sur {0,1} est un code préfixe complet si et seulement si il est le code des feuilles d’un arbre binaire entier. Ce code de l’exemple est préfixe complet, il n’y aura donc pas ambiguïté lors du décodage. On peut ainsi compléter la lecture de la séquence on trouve : R D F B etc. 1 1 F 1 C D B A

160 Problématique Problème : Codage arborescent Entrée : un texte à coder;
Chap. 7 : Application Problématique Problème : Codage arborescent Entrée : un texte à coder; Sortie : un code préfixe complet; Relation : le code préfixe complet qui minimise la taille du texte codé;

161 Chap. 7 : Application Algorithme de Huffman Il s’agit d’un algorithme statistique qui affecte à chaque caractère d’un texte en clair un code (sous forme binaire). La longueur du code d’une lettre est fonction de la fréquence d’apparition de la lettre; 2) Le décodage est rendu facile par le choix d’un code « préfixe » complet; 3) Il existe une version dite statique et une version dite adaptative ; Pour le codage adaptatif les fréquences sont mises à jours après chaque compression de caractère.

162 Construction et représentation
Chap. 7 : Application Construction et représentation Soit la séquence « abracadabra » 11 6 4 2 Initialisation : on construit une forêt d’arbres binaires chacun formé d’une seule feuille. Chaque feuille correspond à une lettre et a pour valeur la fréquence d’apparition de la lettre dans le texte. Itération : On fusionne 2 des arbres dont la valeur est minimale. Le nouvel arbre obtenu remplace les deux arbres et sa valeur est égale à la somme des valeurs des deux arbres supprimés.. Arrêt : On arrête le processus lorsqu’il ne reste plus qu’un arbre dans la forêt. 5 1 1 2 2 a c d b r

163 Implémentation chaîne : liste d’entiers;
Chap. 7 : Application Implémentation On appellera «code » le produit cartésien sur les quatre champs : chaîne : liste d’entiers; taille : entier; père[] : tableau d’entiers; fréquence[] : tableau d’entier; Les opérations : nouveauCode(s); code.arbre(); code.codage(i); code.compression(); Le constructeur nouveauCode(s) compte le nombre de lcaractères différents dans s; Le résultat est positionné dans taille, de taille « taille » est renseigné; Le tableau fréquence est de taille 2*taille - 1 (qui représente l’arbre). La méthode code.arbre renseigne le champs « père »; La méthode code.codage(i) retourne le code binaire (sous forme de liste de booléens) correspondant au caractère « i »; La méthode code.compression(s) retourne le code correspondant à la chaîne de caractère « s ».

164 Méthode code.arbre() Algorithme code.arbre() Données : self : code;
Chap. 7 : Application Méthode code.arbre() Algorithme code.arbre() Données : self : code; Résultat : / ; (le tableau père[] est màj) Variables : maFile : filePriorité; x,y : entier; Début pour (i=1 à taille) faire maFile.insérer(i,frequence[i]); pour (i=taille+1 à 2.taille -1) faire x  maFile.minimum(); maFile  maFile.extraire(); y  maFile.minimum(); maFile  maFile.extraire(); frequence[i]  frequence[x] + frequence[y]; père[x]  -i; père[y]  i; maFile  maFile.insérer(i,frequence[i]); fin La mise à jour du champs père[] est piloté par une file de priorité (la valeur traité d’abord, dans cette file) sont celle dont la valeur de priorité est minimale. De plus on change un peu les spécification de ce T.D.A. car l’insertion dans la file prend un couple en paramètre.

165 Méthode code.codage() Algorithme code.codage()
Chap. 7 : Application Méthode code.codage() Algorithme code.codage() Données : self : code; i : entier; Résultat : codage: liste de booléens; Début si (père[i]=0) alors retourner nil; sinon retourner codage(|père[i]|) + nouvelleListe( père[i] >0 ); fin Idée (par récursion) : si le père de i est positif, alors i est fils droit et le booléen local vaux 1. On concatène ce 1 avec le codage supérieur.

166 Méthode code.compression()
Chap. 7 : Application Méthode code.compression() Algorithme code.compression() Données : self : code; Résultat : codage: liste de booléens; Début codage  nil; p  chaîne; Tantque (p != nil) faire; codage  codage + codage(p.contenu); p  p.suivant; FinTantque retourner codage; fin

167 Transmission Deux choix sont possibles pour la transmission :
Chap. 7 : Application Transmission Deux choix sont possibles pour la transmission : soit l’on transmet une séquence correspondant au codage retenu tel que 0(a)10(b)1100(d)1101(c)111(r); soit on ne transmet que les fréquences et il reste à la charge du destinataire de reconstruire le code; Remarque : si l’on décide de transmettre la liste des fréquences, il est plus approprié de transmettre une liste de fréquences plus compact mais qui préserve l’arbre obtenu. En effet plusieurs suites de fréquences différentes produisent le même arbre de codage.


Télécharger ppt "Université Blaise Pascal"

Présentations similaires


Annonces Google