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

Année 2014-2015 Carole Blanc.  Carole Blanc :  Site WEB :

Présentations similaires


Présentation au sujet: "Année 2014-2015 Carole Blanc.  Carole Blanc :  Site WEB :"— Transcription de la présentation:

1 Année 2014-2015 Carole Blanc

2  Carole Blanc : carole.blanc@labri.frcarole.blanc@labri.fr  Site WEB : http://dept-info.labri.u-bordeaux.fr/~blanc/ENS/ASD/  4 groupes de TD : ◦ 1-G Mélançon, 2-C. Blanc, 3- C Gavoille, 4- S. Gueorguieva  3 DS en séance de TD (coef 0,4).  1 examen en fin de semestre (coef 0,6). ◦ Note= 0.6*EX +0.4*max(CC, EX)  2 sessions (janvier et juin).

3  Complexité  Récursivité  Type abstrait  Containeur  Implémentation

4 Définition 1.1 L'efficacité d'un algorithme est mesurée par son coût (complexité) en temps et en mémoire. La complexité d'un algorithme se mesure en calculant : ◦ le nombre d'opérations élémentaires, ◦ la taille de la mémoire nécessaire, pour traiter une donnée de taille n.

5 On considèrera dans ce cours que la complexité des instructions élémentaires les plus courantes sur un ordinateur a un temps d'exécution constant égal à 1. Centre d’intérêt pour l'algorithmique c'est l'ordre de grandeur au voisinage de l'infini de la fonction qui exprime le nombre d'instructions ou la taille de la mémoire. Question : L’infini de quoi ?

6 Définition 1.2 On définit les trois complexités suivantes : ◦ Complexité dans le pire des cas : C > A (n)=max{C A (d),d donnée de taille n} ◦ Complexité dans le meilleur des cas : C < A (n)=min{C A (d),d donnée de taille n} ◦ Complexité en moyenne : où Pr(d) est la probabilité d'avoir en entrée une instance d parmi toutes les données de taille n.

7 Cas Particulier : Problème NP-complet C’est un problème pour lequel on ne connait pas d'algorithme correct efficace : réalisable en temps et en mémoire. L'ensemble des problèmes NP-complets ont les propriétés suivantes :  Si on trouve un algorithme efficace pour un problème NP complet alors il existe des algorithmes efficaces pour tous,  Personne n'a jamais trouvé un algorithme efficace pour un problème NP-complet,  Personne n'a jamais prouvé qu'il ne peut pas exister d'algorithme efficace pour un problème NP-complet particulier. Le plus célèbre est le problème du voyageur de commerce.

8 Définition 1.3: Lorsqu'un algorithme contient un appel à lui-même, on dit qu'il est récursif. Lorsque deux algorithmes s'appellent l'un l'autre on dit que la récursivité est croisée Complexité Un algorithme récursif nécessite de conserver les contextes récursifs des appels. La récursivité peut donc conduire à une complexité mémoire plus grande qu'un algorithme itératif.

9 Exemple : calcul de la fonction factorielle : fonction facRecur(val :entier):entier; debut si n==0 alors retourner(1) sinon retourner(n*facRec(n-1)) finsi fin finfonction

10 Exemple : calcul de la fonction factorielle fonction facIter(val n:entier):entier; debut var i,p:entier; p=1: pour i=2 à n faire p=p*i; finpour retourner(p) fin Finfonction La fonction factIter est meilleure en temps et mémoire (voir).voir

11 Définition 1.4 : Un algorithme récursif présente une récursivité terminale si et seulement si la valeur retournée par cet algorithme est une valeur fixe, ou une valeur calculée par cet algorithme. L'algorithme facRecur ne présente pas de récursivité terminale.

12 fonction facRecur(val n:entier):entier; debut si n==0 alors retourner(1) sinon retourner(n*facRec(n-1)) finsi fin finfonction

13 Exemple fonction facRecurTerm(val n:entier; val res:entier):entier; debut si n==0 alors retourner(res) sinon retourner(facRecurTerm(n-1,n*res)) finsi fin finfonction L'algorithme facRecurTerm présente une récursivité terminale. La factorielle se calcule par l'appel facRecurTerm(n,1)

14 Intérêt : les compilateurs détectent cette propriété et optimisent le stockage de l'environnement de la fonction. Ainsi facRecurTerm aura une complexité identique à facIter. ATTENTION. Dans le cas d'un algorithme présentant deux appels récursifs, rendre la récursivité terminale ne permet pas obligatoirement au compilateur d'obtenir une complexité inférieure.

15 Définition 1.5 : Un type abstrait est un triplet composé : ◦ d'un nom, ◦ d'un ensemble de valeurs, ◦ d'un ensemble d'opérations (souvent appelé primitives) définies sur ces valeurs. D'un point de vue complexité, on considère que les primitives (à part celle d'initialisation si elle existe) ont une complexité en temps et en mémoire en O(1). Pour désigner un type abstrait on utilise une chaine de caractères.

16 Exemple Les nombres complexes ne sont pas des types de bases. On peut les définir comme un type abstrait : ◦ nom : nombreComplexe ◦ ensemble de valeur : réel×réel ◦ primitives :  multiplication : (nombreComplexe × nombreComplexe) → nombreComplexe  addition : (nombreComplexe × nombreComplexe) → nombreComplexe  module : nombreComplexe → réel

17  Fin 1 er cours

18 Définition 1.6 : Un containeur est un type abstrait permettant de représenter des collections d'objets ainsi que les opérations sur ces objets. Les collections que l'on veut représenter peuvent être ordonnées ou non, numériques ou non. L'ordre est parfois fourni par un évènement extérieur. Les collections d'objets peuvent parfois contenir des éléments identiques.

19 Primitives :  Accès valeur : containeur → objet  Modification creerContaineur: containeur → vide ajouter : containeur X objet → vide supprimer : containeur X objet → vide detruireContaineur : containeur → vide Exemple Un ensemble de nombres complexes peut être défini par un containeur dont les objets sont des nombreComplexe.

20 Définition 1.7 : L'implémentation consiste à choisir une structure de données et les algorithmes associés pour réaliser un type abstrait La structure de données utilisée pour l'implémentation peut elle-même être un type abstrait. L'implémentation doit respecter la complexité des primitives à part celle d'initialisation (celle-ci ne s'exécutera qu'une fois).

21 Exemple Le type abstrait nombreComplexe peut être implémenté de la manière suivante : nombreComplexe=structure r:réel; i:réel; Finstructure var c : nombreComplexe; nombre Complexe NomType rréel i Nom variableType cnombreComplexe c.rréel c.iréel

22 Exemple Le type abstrait Etudiant peut être implémenté de la manière suivante : Etudiant=structure nom:chainedecar; prenom:chainedecar; numero:entier note:reel Finstructure var E1 : Etudiant; Var E2 :Etudiant; E1.numero>E2.numero Nom variableType E.notereel E.numeroentier E.nomchaine

23 Exemple Le type abstrait nombreComplexe peut être implémenté de la manière suivante : nombreComplexe=structure r:réel; i:réel; Finstructure fonction op::*(val a,b:nombreComplexe):nombreComplexe; var c:nombreComplexe; debut c.r=a.r*b.r-a.i*b.i; c.i=a.r*b.i+a.i*b.r; retourner(c) fin

24 Exemple fonction op::+(val a,b:nombreComplexe):nombreComplexe; var c:nombreComplexe; debut c.r=a.r+b.r; c.i=a.i+b.i; retourner(c) fin fonction module(val a:nombreComplexe):réel; debut retourner(sqrt(a.r*a.r+a.i*a.i)) fin

25 Exemple Un containeur de nombreComplexe peut être implémenté par un tableau de nombreComplexe. containeur d'objet=tableau[1..N]de structure v:objet; b:booleen; Finstructure T 123456N vobjet bbooléen

26 Modification fonction creerContaineur(ref C:containeur de nombreComplexe):vide; var i:entier; debut pour i allant de 1 à N faire C[i].b=faux; finPour; fin C 12345…N v nombreComplexe bFFFFFF…FFF booléen Complexité : ?

27 Modification fonction ajouter(ref C: containeur de nombreComplexe;val x:nombreComplexe):vide var i:entier; debut i=1; tant que i<=N et C[i].b faire i=i+1; fintantque si i<=N alors C[i].v=x; C[i].b=vrai finsi fin C 12345…N v c1c21c5c2 nombreComplexe bVVVVFF…FFF booléen Complexité : ?

28 Modification fonction supprimer(ref C: containeur de nombreComplexe;val x:nombreComplexe):vide var i:entier; debut i=1; tant que i<=N et C[i].v!=x faire i=i+1; fintantque si i<=N alors C[i].b=faux finsi fin C 12345…N v c1c21c5c2 nombreComplexe bVVFVF…FFF booléen Complexité : ?

29 Modification fonction supprimer(ref C: containeur de nombreComplexe;val x:nombreComplexe):vide var i:entier; debut i=1; tant que i<=N faire si C[i].v == x et C[i].b alors C[i].b=Faux break finsi i=i+1; fintantque fin Complexité : ?

30 Modification fonction detruireContaineur(ref C : containeur de nombreComplexe):vide debut pour i allant de 1 à N faire C[i].b=faux; finPour; fin Complexité : ?

31 Accès fonction valeur(ref C : containeur de nombreComplexe):nombreComplexe; /* retourne le 1er nombre complexe présent/* var i:entier; debut i=1; tant que i<=n et !C[i].b faire i=i+1; fintantque si i<=n alors retourner(C[i].v) sinon retourner(NULL) finsi fin 2 conditions d’arrêtTest en sortie de boucle Complexité : ?

32  Définition  Liste simplement chainée  Liste doublement chainée  Implémentation par un tableau du type listeSC  Implémentation par allocation dynamique du type listeSC

33 Définition 2.1  Une liste est un containeur tel que le nombre d'objets (dimension ou taille) est variable,  L'accès aux objets se fait indirectement par le contenu d'une clé qui le localise de type curseur.

34 Un curseur est un type abstrait dont l'ensemble des valeurs sont des positions permettant de localiser un objet dans le containeur. Dans le cas où il n'y a pas de position, la valeur par défaut est NIL. Si c est un curseur, les primitives considérées dans ce cours sont les suivantes :  accès à l'élément désigné par le curseur : contenu(c): curseur → objet  accès à la valeur du curseur : getCurseur(c) : curseur → valeur_de_curseur  positionnement d'un curseur : setCurseur(c,valeur) : curseur X valeur_de_curseur → vide  existence d'un élément désigné par le curseur : estVide(c) : curseur → {vrai,faux} La manipulation des éléments de la liste dépend des primitives définies comme s'exécutant en temps O(1).

35 Définition 2.2 Une liste est dite simplement chainée si les opérations suivantes s'effectuent en O(1). valeur accès fonction valeur(val L:liste d'objet):objet; /* si la clé==NIL alors le résultat est NULL */ debutListe fonction debutListe(ref L:liste d'objet); /* positionne la clé sur le premier objet de la liste */ suivant fonction suivant(ref L:liste d'objet); /* avance la clé d'une position dans la liste */ listeVide fonction listeVide(val L:liste d'objet): booleen; /* est vrai si la liste ne contient pas d'élément */ getCléListe fonction getCléListe(val L: liste d'objet):curseur; /* permet de récupérer la clé de la liste */

36 Modification supprimerEnTete fonction supprimerEnTete(ref L:liste d'objet):vide; /* supprime un objet en debut de liste, la clé est positionnée*/ /*sur la tête de liste */ setCléListe fonction setCléListe(ref L: liste d'objet, val c:curseur):vide; /* permet de positionner la clé de la liste*/ detruireListe fonction detruireListe(ref L:liste d'objet):vide;

37 Modification creerListe fonction creerListe(ref L:liste d'objet):vide; insererApres fonction insererApres(ref L:liste d'objet, val x:objet;):vide; /* insère un objet après la clé, la clé ne change pas */ insererEnTete fonction insererEnTete(ref L:liste d'objet, val x:objet):vide; /* insère un objet en debut de liste, la clé est positionnée sur la tête de liste */ supprimerApres fonction supprimerApres(ref L:liste d'objet):vide; /* supprime l'objet après la clé, la clé ne change pas */

38 Détection fin de liste estFinListe fonction estFinListe(val L:liste d'objet):booléen; debut retourner(valeur(L)==NULL) fin Chercher un élément dans une liste chercher fonction chercher(ref L:liste d'objet; ref x:objet): booleen; debut debutListe(L); tant que !estFinListe(L) et valeur(L)!=x faire suivant(L); fintantque retourner (!estFinListe(L)) /* la clé vaut NIL ou est positionné sur l'objet */ fin Finfonction Complexité: minimum : O(1) maximum : O(n )

39 Supprimer un élément dans la liste s'il existe supprimer fonction supprimer(ref L:liste d'objet; ref x:objet): vide; var tmp:curseur; /* on suppose que l'objet se trouve dans la liste */ debut debutListe(L); tmp=NIL; /*on cherche l’objet dans la liste */ tant que !estFinListe(L) et contenu(getCléListe(L))!=x faire tmp= getCléListe(L); suivant(L); fintantque.

40 Supprimer un élément dans la liste s'il existe supprimer fonction supprimer(ref L:liste d'objet; ref x:objet): vide;... /* 2 cas en sortie de la boucle tantque */ si tmp==NIL alors /*la clé est sur la tête de liste */ supprimerEnTete(L) sinon setCléListe(L,tmp); /*la clé est sur l'objet précédent l'objet à supprimer*/ supprimerAprès(L); finsi fin finfonction Complexité: minimum : O(1) maximum : O(n)

41 supprimer fonction supprimer(ref L:liste d'objet; ref x:objet): vide; var tmp:curseur; debut debutListe(L); tmp=NIL; tant que !estFinListe(L) et contenu(getCléListe(L))!=x faire tmp= getCléListe(L); suivant(L); fintantque si tmp==NIL alors supprimerEnTete(L) sinon setCléListe(L,tmp); supprimerAprès(L) finsi fin finfonction

42 Exercice: Réfléchir aux problèmes que soulèvent l'introduction de getCléListe et surtout setCléListe ? Que faut-il en déduire? Doit-on vraiment les garder?

43 Définition 2.2: Une liste doublement chainée est une liste pour laquelle les opérations en temps O(1) sont celles des listes simplement chainées auxquelles on ajoute les fonctions d'accès fonction finListe(ref L:liste d'objet):vide; /* positionne la clé sur le dernier objet de la liste */ fonction precedent(ref L::liste d'objet): vide; /* recule la clé d'une position dans la liste */

44 Supprimer un élément fonction supprimer(ref L:liste d'objet; ref x:objet): booleen; debut si chercher(L,x) alors précédent(L); si valeur(L)!=NULL alors supprimerAprès(L); sinon supprimerEnTete(L) fin retourner(vrai) sinon retourner(faux) finsi fin finfonction Complexité : minimum : O(1) maximum : O(n)

45 Chaque élément du tableau est une structure ◦ objet ◦ indexSuivant Le champ indexSuivant désigne une entrée du tableau. Ainsi l'accès au suivant est en complexité O(1). Pour une liste de caractère la zone de stockage peut donc être décrite par : stockListe = tableau[1..tailleStock] d'elementListe ; elementListe=structure valeur : car; indexSuivant : entier ; finstructure;

46 Dans ce contexte, le type curseur est un entier compris entre 1 et tailleStock. Il faut coder la valeur NIL : on peut par exemple choisir 0 La valeur du champ indexSuivant est donc un entier compris entre 0 et tailleStock. Le premier élément doit être accessible en O(1), il faut donc conserver son index.

47 On peut donc représenter une liste par la structure suivante : listeSC_Car=structure tailleStock:entier; vListe:stockListe; premier:curseur; cle:curseur; finstructure; Le tableau de stockage étant grand mais pas illimité, il faudra prévoir que l'espace de stockage puisse être saturé.

48 Primitives d'accès Ces fonctions sont immédiates. fonction debutListe(ref L:listeSC_Car):vide; debut L.cle=L.premier; fin finfonction fonction suivant(ref L:listeSC_Car):vide; debut L.cle=L.vListe[L.cle].indexSuivant; fin finfonction

49 Primitives d'accès fonction listeVide(ref:listeSC_Car): booléen; debut retourner(L.premier==0); fin finfonction

50 Gestion de l'espace de stockage Pour ajouter un élément, il faut pouvoir trouver un élément "libre" dans le tableau. Une solution compatible avec la complexité des primitives consiste à gérer cet espace de stockage en constituant la liste des cellules libres (voir un exemple) On modifie donc en conséquence la description de listeSC_Car :voir un exemple listeSC_Car=structure tailleStock:entier; vListe:stockListe; premier:curseur; premierLibre:curseur; cle:curseur; finstructure;

51 Gestion de l'espace de stockage Par convention, l'espace de stockage sera saturé lorsque l'index premierLibre vaut 0 (la liste des cellules libres est vide). On définit donc la fonction de test : fonction listeLibreVide(ref L:listeSC_Car):booléen; debut retourner(L.premierLibre==0); fin finfonction

52 Gestion de l'espace de stockage On définit deux primitives liées à la gestion de la liste des libres : 1. mettreCellule : insère une cellule libre en tête de la liste des cellules libres L’opération correspondante est de type insererEnTete fonction mettreCellule (ref L:listeSC_Car,val P:curseur):vide; debut L.vListe[P].indexSuivant=L.premierLibre; L.premierLibre=P; fin finfonction

53 Gestion de l'espace de stockage On définit deux primitives liées à la gestion de la liste des libres : 2. prendreCellule : prend la cellule libre en tête de la liste des cellules libres. L’opération correspondante est de type supprimerEnTete. fonction prendreCellule (ref L:listeSC_Car):curseur; var nouv:curseur; debut nouv=L.premierLibre; L.premierLibre=L.vListe[nouv].indexSuivant; retourner nouv; fin finfonction

54 Deux primitives de modifications fonction creer_liste(ref L:listeSC_Car):vide; var i:curseur; debut L.tailleStock=tailleMax; L.premier=0; L.premierLibre=1; pour i allant de 1 à L.tailleStock-1 faire L.vListe[i].indexSuivant=i+1; finpour L.vListe[tailleStock].indexSuivant=0; L.cle=0; fin finfonction

55 Deux primitives de modifications fonction insérerAprès (ref L:listeSC_Car;val x:car):booléen; var tmp,nouv:curseur; debut si L.cle==0 ou L.premierLibre==0 alors retourner faux; sinon tmp=L.cle; nouv=prendreCellule(L); L.vListe[nouv].valeur=x; L.cle=L.vListe[L.cle].indexSuivant; /*suivant(L)*/ L.vListe[nouv].indexSuivant=L.cle; L.vListe[tmp].indexSuivant=nouv; L.cle=tmp; retourner vrai; finsi; fin ; finfonction

56 Réfléchir aux problèmes que soulèvent l'introduction de getCléListe et surtout setCléListe ? Que déduire? Faut-il vraiment les garder? Dans ce choix d’implémentation on a curseur=entier. Supposons tailleStock=1000. La séquence suivante mènera à une incohérence. setCléListe(L,10000); suivant(L); Le fait d'avoir introduit ces primitives permet lors de l'utilisation du type abstrait de modifier la clé de type curseur et donc par la même de pouvoir rendre la structure de donnée incohérente en cas de mauvaise utilisation.

57 Pointeur : Définition et syntaxe Définition : Un pointeur est une variable qui contient une adresse mémoire. Pour déclarer un pointeur on écrit : nom_pointeur=curseur; Par convention un pointeur qui ne donne accès à aucune adresse contient la valeur NIL. Pour accéder à l'emplacement mémoire désigné par le pointeur on écrit : nom_pointeur^

58 Pointeur : Définition et syntaxe La primitive new permet d'allouer dynamiquement de la mémoire au cours d'une exécution. On écrira: new(nom_pointeur); Lorsque la mémoire n'est plus utilisée par le pointeur il faut impérativement la libérer. La primitive delete permet de libérer la mémoire allouée par l'intermédiaire d'un pointeur, on écrira : delete(nom_pointeur);

59 Chaque élément de la liste est une structure : (valeurElement,pointeurSuivant) Le champ pointeurSuivant est une adresse en mémoire, par suite, l'accès au suivant est en complexité O(1). Dans ce contexte le type curseur est un pointeur vers un élément. La zone de stockage peut donc être décrite par : cellule=structure valeurElement:car; pointeurSuivant:^cellule; finstructure; curseur=^cellule;

60 La zone de stockage peut donc être décrite par : cellule=structure valeurElement:car; pointeurSuivant:^cellule; finstructure; curseur=^cellule; listeSC_car=structure premier:curseur; cle:curseur; finstructure NIL correspond donc à l'absence d'élément suivant.

61  Primitives d'accès fonction listeVide(val L:listeSC_car):booléen; debut retourner L.premier==NIL; fin finfonction listeVide est utilisée si nécessaire avant les autres. fonction valeur(val L:listeSC_car):car; debut retourner L.cle^.valeurElement; fin finfonction

62  Primitives d'accès fonction premier(val L:listeSC_car):vide; debut L.cle=L.premier; fin; finfonction fonction suivant(val L:listeSC_car):vide; debut L.cle=L.cle^.pointeurSuivant; fin finfonction

63  Trois primitives de modifications fonction creer_liste(ref L:listeSC_Car):vide; debut L.premier=NIL; L.cle =NIL; fin finfonction

64  Trois primitives de modifications On suppose que la clé est au debut de la liste fonction supprimerEnTete(ref L:listeSC_Car):vide; var P:curseur; debut P=L.premier; suivant(L); L.premier=L.cle; delete(P); fin finfonction

65  Trois primitives de modifications fonction insererApres(val x:car; ref :listeSC_Car):vide; var nouv:curseur; debut new(nouv); nouv^.valeurElement=x; nouv^.pointeurSuivant=L.cle^.pointeurSuivant; L.cle^.pointeurSuivant=nouv; fin finfonction

66  L'implémentation dans un tableau permet d'avoir un bloc contigu de mémoire ce qui va minimiser les accès disques. Ceci n'est pas le cas pour l'implémentation par pointeurs.  L'implémentation dans un tableau nécessite de fixer au préalable le nombre maximum de cellules qui va contraindre fortement les applications : la structure de donnée peut avoir beaucoup trop de cellules ou au contraire trop peu.  L'implémentation par pointeur va être très dépendante de l'implémentation des modules d'allocation dynamique du langage choisi

67  Définitions  Primitives de piles, exemples  Primitives de files, exemples  Implémentation des piles  Implémentation des files

68 Les piles et les files sont des containeurs dans lesquels on ne peut accéder qu'à un objet particulier. Définition 3.1. : Dans une pile, l’objet accessible est le dernier inséré (LIFO, Last-In, First-Out). Définition 3.2: Dans une file, l‘objet accessible est le plus ancien dans la file (FIFO, First-In, First-Out). On écrira pour déclarer des variables : type_pile=pile de objet; type_file=file de objet;

69 Une pile est définie par les opérations suivantes : accès fonction valeur(val P:pile de objet):objet; fonction pileVide(val P:pile de objet):booléen; modification fonction creerPile(ref P:pile de objet):vide; fonction empiler(ref P:pile de objet; val:objet):vide; fonction depiler (ref P:pile de objet):vide; fonction detruirePile(ref P:pile de objet):vide;

70 fonction listeInverse(ref L:listeSC de objet):listeSC de objet; var P:pile de objet; var LR:liste de objet; debut creerListe(LR); creerPile(P); debutListe(L); tant que !finListe(L) faire empiler(P,valeur(L)); suivant(L); fintantque insererEnTete(LR,valeur(P)) depiler(P); tant que non(pileVide(P)) faire insererApres(LR,valeur(P)); suivant(LR); depiler(P); fintantque; detruirePile(P) retourner(LR); fin finfonction

71 Une file est définie par les opérations suivantes : Accès : fonction valeur(val F:file de objet):objet; fonction fileVide(val F:file de objet):booléen; Modification : fonction creerFile(ref F:file de objet):vide; fonction enfiler(ref F:file de objet; val v:objet):vide; fonction defiler(ref F:file de objet):vide; fonction detruireFile(ref F:file de objet):vide;

72 fonction compteFile(ref F:file de entier): entier; var v,compt:entier; debut compt=0; enfiler(F,0); tant que valeur(F)!=0 faire compt=compt+1; v=valeur(F); defiler(F); enfiler(F,v); fintantque; defiler(F); retourner(compt); fin finfonction

73 fonction inverserFile(ref F:file de entier):file d'entier; var P:pile d'entier; var FS:file d'entier; debut creerPile(P); creerFile(FS); enfiler(F,0); tant que valeur(F)!=0 faire v=valeur(F); defiler(F); enfiler(F,v); empiler(P,v); fintantque defiler(F); tant que non(pileVide(P)) faire v=valeur(P); enfiler(FS,v); depiler(P); fintantque; detruirePile(P); retourner(FS); fin finfonction

74 Chaque objet de la pile est un élément du tableau. On doit de plus avoir un champs qui permet d'accéder au sommet de pile. pile d'objet=structure taille:entier; sommet:entier; pile:tableau[1..taille] d'objets; finstructure;

75 accès fonction valeur(ref P:pile de objet):objet; debut retourner(P.pile[P.sommet]); fin finfonction fonction pileVide(ref P:pile de objet):booléen; debut retourner(P.sommet==0); fin finfonction

76 modification fonction empiler(ref P:pile de objet; x:objet):booleen; /* l'espace de stockage peut être saturé */ debut si P.sommet==P.taille alors retourner(FAUX) sinon P.sommet=P.sommet+1; P.pile[P.sommet]=x; retourner(VRAI) finsi fin finfonction

77 modification fonction depiler(ref P:pile de objet):vide; debut P.sommet=P.sommet-1; fin finfonction fonction creerPile(ref P:pile de objet):pile de objet; debut P.sommet=0; fin finfonction

78 Chaque objet de la pile est un objet de la listeSC. pile d'objet=listeSC de objet; accès : fonction valeurPile(ref P:pile de objet):objet; debut debutListe(P); retourner(valeurListe(P)); fin finfonction fonction pileVide(ref P:pile de objet):booléen; debut retourner(listeVide(P)); fin finfonction

79 modification fonction empiler(ref P:pile de objet; x:objet):vide; debut insérerEnTete(P,x) fin finfonction fonction depiler(ref P:pile de objet):vide; debut supprimerEnTete(P); fin finfonction

80 modification fonction creerPile(ref P:pile de objet):vide; debut creerListe(P); fin finfonction

81 Chaque objet de la file est un élément du tableau. On utilise le tableau de manière circulaire avec un pointeur donnant le premier et un autre donnant le dernier. file d'objet=structure taille : entier; premier : entier; dernier : entier; plein : booléen; file : tableau[0..taille-1] d'objets; finstructure;

82 accès fonction valeur(ref F:file de objet):objet; debut retourner(F.file[F.premier]); fin finfonction fonction fileVide(ref F:file de objet):booléen; debut retourner(F.premier==F.dernier & non(F.plein)); fin finfonction

83 Modification fonction enfiler(ref F:file de objet; x:objet):booleen; debut si F.plein alors retourner(FAUX) sinon F.file[F.dernier]=x; F.dernier=(F.dernier+1) mod F.taille; F.plein=F.dernier==F.premier; retourner(VRAI) finsi fin finfonction

84 Modification fonction creerFile(ref F:file de objet):file de objet; debut F.premier= 0; F.dernier= 0; F.plein=FAUX; fin finfonction

85 Modification fonction defiler(ref F:file de objet):vide; debut F.premier=(F.premier+1) mod F.taille; F.plein=Faux fin finfonction

86 Chaque objet de la file est un objet de la liste_DC car il faut un accès au dernier. file d'objet=liste_DC de objet; Accès : fonction fileVide(ref F:file de objet):booléen; debut retourner(listeVide(F)); fin finfonction

87 modification fonction enfiler(ref F:file de objet; x:objet):vide; debut dernier(F); insererApres(F,x); fin finfonction fonction defiler(ref F:file de objet):vide; debut supprimerEnTete(F); fin finfonction

88 modification fonction creerFile(ref F:file de objet):vide; debut creerListe(F); fin finfonction

89 cellule=structure valeurElement:objet; pointeurSuivant:^cellule; finstructure; curseur=^cellule; file d'objet=structure premier:curseur; dernier:curseur finstructure

90 accès fonction valeurFile(ref F:file de objet):objet; debut retourner(F.premier^.valeurElement); fin finfonction fonction fileVide(ref F:file de objet):booléen; debut retourner(F.premier==NIL); fin finfonction

91 modification fonction enfiler(ref F:file de objet; x:objet):vide; var c:curseur; debut new(c); c^.valeurElement=x; c^.pointeurSuivant=NIL; si F.premier==NIL alors F.premier=c finsi F.dernier^.pointeurSuivant=c; F.dernier=c; fin finfonction

92 modification fonction defiler(ref F:file de objet):vide; var c:curseur; debut c=F.premier; si F.premier=F.dernier alors F.dernier=NIL finsi F.premier=c^.pointeurSuivant; delete(c) fin finfonction

93 modification fonction creerFile(ref F:file de objet):vide; debut F.premier=NIL; F.dernier=NIL; fin finfonction

94 modification fonction detruireFile(ref F:file de objet):vide; debut tantque !fileVide(F) faire defiler(F) fintantque fin finfonction

95  Arbre et arborescence  Arbres binaires  Parcours d'un arbre binaire  Implémentation d'un arbre binaire  Retour sur les arborescences  Parcours d'un arbre planaire  Implémentation d'un arbre planaire

96 Définition 4.1: Un arbre est un graphe connexe sans cycle. Un sous arbre est un sous graphe d'un arbre. Propriété 4.1: Si un arbre a n sommets alors il a n-1 arêtes. Idée de la démonstration: ceci s'appuie sur les deux propriétés suivantes des graphes connexes.  Tout graphe connexe ayant n sommets a au moins n-1 arêtes.  Tout graphe connexe ayant n sommet et au moins un cycle a au minimum n arêtes. La taille d'un arbre est le nombre de sommets de l'arbre.

97 Propriété 4.2: Entre deux sommets quelconques d'un arbre, il existe une unique chaîne les reliant. Idée de la démonstration : Pour deux sommets quelconques  Il ne peut exister deux chaines différentes les reliant sinon il y aurait un cycle dans l'arbre.  Il existe au moins une chaine puisque un arbre est un graphe connexe.

98 ArbreArborescence Définition 4.2: Une arborescence est définie à partir d'un arbre en choisissant un sommet appelé racine et en orientant les arêtes de sorte qu'il existe un chemin de la racine vers tous les autres sommets.

99 Définitions 4.3 :  On appelle fils d'un sommet s tout sommet s' tel que (s,s') est une arête de l'arbre.  On notera qu'une arborescence est un exemple d'ensemble partiellement ordonné (relation d'ordre "fils de").  On appelle feuille de l'arbre un sommet qui n'a pas de successeur. Tout autre sommet est appelé sommet interne.  On appelle hauteur d'un sommet de l'arbre la longueur du chemin de la racine à ce sommet.

100 Définition 4.4: Un arbre planaire est défini en ordonnant les arêtes sortantes de chaque sommet. On notera qu'un arbre planaire est un exemple d'ensemble totalement ordonné (relation "est fils ou est frère à droite"). Définition 4.5: Un arbre binaire est un arbre planaire dont chaque sommet a au plus deux fils. Définition 4.6: Un arbre binaire complet est un arbre binaire dont chaque sommet interne a exactement deux fils..

101 Racine Premier Fils Frère droit Arbre planaire

102 Arbre Binaire

103 Arbre Binaire complet

104 Propriété 4.3: Tout sommet x d'un arbre binaire vérifie l'une des deux propriétés suivantes:  x est une feuille,  x a un sous arbre binaire dit gauche de racine G(x) et un sous arbre binaire droit de racine D(x). X G(X)D(X) feuille

105 Définition 4.7: Un arbre binaire parfait est un arbre binaire complet dans lequel toutes les feuilles sont à la même hauteur dans l'arbre. Théorème 4.1: Un arbre binaire de taille n a une hauteur moyenne de log 2 (n).

106 Théorème 4.2: Il existe une bijection qui transforme un arbre planaire ayant n sommet en un arbre binaire complet ayant 2n+1 sommets.bijection Du fait de ce théorème, on ne considère dans un premier temps que le type arbre binaire que l'on nommera arbreBinaire.

107 Chaque sommet permet d'accéder à deux sommets :  le fils gauche.  le fils droit. Ce type sera nommé sommet. Chaque sommet permet également d'accéder à l'objet qu'il stocke. Un arbre binaire peut être vu comme un curseur indiquant le sommet racine. De la même manière un sommet est un curseur. On a donc : arbreBinaire=curseur; sommet=curseur ;

108 Le type sommet présente les primitives suivantes : Accès : fonction getValeur(val S:sommet):objet; /* vaut NULL si le sommet n'existe pas /* fonction filsGauche(val S:sommet):sommet; /* vaut NIL si S n'a pas de fils gauche */ fonction filsDroit(val S:sommet):sommet; /* vaut NIL si S n'a pas de fils droit */ fonction pere(val S:sommet):sommet; /* vaut NIL si S est la racine de l'arbre */

109 Modification : fonction setValeur(ref S:sommet;val x:objet):vide; /* affecte au sommet S la valeur x */ fonction ajouterFilsGauche(ref S:sommet,val x:objet):vide; /* filsGauche(S)==NIL doit être vérifié */ fonction ajouterFilsDroit(ref S:sommet,x:objet):vide; /* filsDroit(S)==NIL doit être vérifié */ fonction supprimerFilsGauche(ref S:sommet):vide; /* filsGauche(S) est une feuille */ fonction supprimerFilsDroit(ref S:sommet):vide; /* filsDroit(S) est une feuille */ fonction detruireSommet(ref S:sommet):vide; /* S est une feuille */

110 Modification : fonction creerArbreBinaire(val Racine:objet):sommet; fonction detruireArbreBinaire(ref A:arbreBinaire d'objet):vide; Détection de feuille fonction estFeuille(val S:sommet):booléen; debut retourner(filsGauche(S)==NIL et filsDroit(S)==NIL) fin

111 Le parcours d'un arbre binaire consiste à donner une liste de sommets dans l'arbre. Le prototype d'algorithme suivant permet d'effectuer les parcours selon les algorithmes associés aux traitements à partir d'un sommet de l'arbre. 1 1 1 2 3 2 1 1 2 3 2 3 3 2 1 1 2 3 3 3 2 e r ai z m g

112 fonction parcoursArbreBinaire(val A:arbreBinaire d'objet):vide; // Déclarations locales debut // traitement1; si estFeuille(A)alors // traitement2; sinon // traitement3; si filsGauche(A)!=NIL alors // traitement4; parcoursArbreBinaire(filsGauche(A)); // traitement5; finsi // traitement6; si filsDroit(A)!=NIL alors // traitement7; parcoursArbreBinaire(filsDroit(A)); // traitement8; finsi // traitement9; finsi // traitement1O; fin

113

114 1 1 1 2 3 2 1 1 2 3 2 3 3 2 1 1 2 3 3 3 2 e r ai z m g Parcours hiérarchique : e,r,g,a,i,m,z Parcours préfixe : e,r,a,i,z,g,m Parcours infixe : a,r,z,i,e,g,m Parcours postfixe : a,z,i,r,m,g,e

115 Affichage des valeurs des sommets pour un parcours donné Soit un arbre étiqueté par des caractères. On considère que l'on dispose de la fonction qui affiche un caractère : fonction afficher(val n:entier):vide; Affichage dans le parcours préfixe pas de déclarations locales. traitement 2, 3 : afficher(valeur(A)); Affichage dans le parcours infixe : pas de déclarations locales. traitement 2, 6: afficher(valeur(A)); Affichage dans le parcours postfixe pas de déclarations locales. traitement 2, 9 : afficher(valeur(A));

116 Lister les étiquettes d'un arbre dans un tableau fonction arbre2Tableau(val A:arbreBinaire d'entier; ref T:tableau[1..N] d'entier; ref i:entier):vide; debut i=i+1; T[i]=valeur(A); si !estFeuille(A)alors si filsGauche(A)!=NIL alors arbre2Tableau(filsGauche(A),T,i); finsi si filsDroit(A)!=NIL alors arbre2Tableau(filsDroit(A),T,i); finsi fin

117 Hauteur d'un arbre binaire fonction hauteurArbreBinaire(val s:sommet):entier debut si estFeuille(s)alors retourner(0) sinon var tmp1,tmp2:entier; tmp1=0; tmp2=0; si filsGauche(s)!=NIL alors tmp1= hauteurArbreBinaire(filsGauche(s)); finsi si filsDroit(s)!=NIL alors tmp2=hauteurArbreBinaire(filsDroit(s)); finsi retourner(1+max(tmp1,tmp2)); finsi fin

118 Hauteur d'un arbre binaire : Autre version fonction hauteurArbreBinaireSimp(val s:sommet):entier debut si s==NIL alors retourner(-1) sinon retourner(1+ max(hauteurArbreBinaireSimp(filsGauche(s)), hauteurArbreBinaireSimp(filsDroit(s)))); finsi fin Remarque : La fonction hauteurArbreSimp (même si elle est plus courte) a une complexité plus grande que la fonction hauteurArbreBinaire notamment en nombre d'appel récursif. Elle est moins performante.

119 Taille d'un sous-arbre d'un arbre binaire complet. fonction tailleArbreBinaire(val A: arbreBinaire):entier; debut si estFeuille(A) alors retourner(1) sinon retourner(1+tailleArbreBinaire(filsGauche(A)) +tailleArbreBinaire(filsDroit(A)) finsi fin

120 L’implémentation se fait par allocation dynamique. On définit cellule=structure info:objet; gauche:sommet; droit:sommet; pere:sommet; finstructure sommet=^cellule; info gauche droit Pere

121 accès fonction getValeur(val S:sommet):objet; debut retourner(S^.info); fin fonction filsGauche(val S:sommet):sommet; debut retourner(S^.gauche) fin

122 modification fonction creerArbreBinaire(val racine:objet):sommet; var tmp:sommet; debut new(tmp); tmp^.info=racine; tmp^.gauche=NIL; tmp^.droit=NIL; tmp^.pere=NIL; retourner(tmp) fin

123 modification fonction ajouterFilsGauche(ref S:sommet,val x:objet):vide; var tmp:sommet; debut new(tmp); tmp^.info=x; tmp^.gauche=NIL; tmp^.droit=NIL; tmp^.pere=S; S^.gauche=tmp; fin

124 modification fonction supprimerFilsGauche(ref S:sommet):vide; var tmp:sommet; debut tmp=S^.gauche; S^.gauche=NIL; delete(tmp); fin

125 modification fonction detruireArbreBinaire( ref A:arbreBinaire d'objet):vide; debut si estFeuille(A)alors delete(A) sinon si filsGauche(A)!=NIL alors detruiresArbreBinaire(filsGauche(A)); finsi si filsDroit(A)!=NIL alors detruireArbreBinaire(filsDroit(A)); finsi delete(A); finsi fin

126 On peut définir un type abstrait sommetArbrePlanaire par les primitives suivantes: accès fonction getValeur(val S:sommetArbrePlanaire):objet; fonction premierFils(val S:sommetArbrePlanaire): sommetArbrePlanaire; fonction frere(val S:sommetArbrePlanaire):sommetArbrePlanaire; fonction pere(val S:sommetArbrePlanaire):sommetArbrePlanaire ;

127 modification fonction creerArbrePlanaire(val racine:objet): sommetArbrePlanaire; fonction ajouterFils(ref S:sommetArbrePlanaire, val x:objet):vide; /* ajoute un fils comme cadet */ fonction supprimerSommet(ref S: sommetArbrePlanaire):vide; /* le sommet doit être une feuille */ fonction detruireArbrePlanaire(ref S: sommetArbrePlanaire):vide; Un arbre planaire est de type sommetArbrePlanaire. C'est un curseur.

128 Le parcours d'un arbre planaire consiste à donner une liste de tous les sommets. fonction parcoursArbrePlanaire(val A:sommetArbrePlanaire):vide; // Déclarations locales var f: sommetArbrePlanaire; debut // traitement 1 ; f= premierFils(A); tant que f!=NIL faire // traitement 2 ; parcoursArbrePlanaire(f); // traitement 3 ; f=frere(f); // traitement 4 fintantque // traitement 5 fin

129 On distingue trois parcours qui conditionnent les algorithmes sur les arbres planaires :  Le parcours hiérarchique qui s'effectue grâce à une file.  Le Parcours préfixe : on liste la racine, les sommets de chaque sous arbre dans l'ordre où les sous arbres apparaissent.  Le Parcours suffixe : on liste les sommets des sous arbres en ordre inverse puis la racine.

130 3 7 212658104109

131 Implémentation dans le type arbreBinaire L'implémentation dans le type arbreBinaire découle du théorème 4.2 On a alors arbrePlanaire=arbreBinaire. Pour un noeud donné :  la primitive filsGauche donne accès au premier fils du noeud.  la primitive filsDroit donne accès au frère du noeud.  la primitive pere donne accès soit au père du noeud soit à son frère précédent. Il faut donc redéfinir la primitive pere pour les arbres planaires.

132 fonction pereArbrePlanaire(val S: sommetArbrePlanaire):sommetArbrePlanaire; var T: sommetArbrePlanaire; debut T=filsGauche(pere(S)); tant que T!=S faire S=pere(S) T=filsGauche(pere(S)); fintantque retourner(pere(S)) fin En utilisant le théorème 4.1, cette dernière primitive à une complexité moyenne O(log 2 n).

133 Implémentation par allocation dynamique Cette implémentation permet de diminuer le temps d'accès au père. cellule=structure info:objet; premierFils:sommet; frere:sommet; pere:sommet; Finstructure Dans cette implémentation, on initialise parfois le champ frere du dernier frère à l'adresse du premier fils. On peut vérifier aisément que les primitives sont toutes réalisables en O(1). L'espace mémoire est le même que celui occupé par une implémentation dans le type arbreBinaire

134 Accès : fonction getValeur(val s:sommetArbrePlanaire):objet; début retourner(s^.info) fin fonction premierFils(val s:sommetArbrePlanaire): sommetArbrePlanaire; début retourner(s^.premierFils) fin

135 Accès : fonction frere(val s : sommetArbrePlanaire) : sommetArbrePlanaire; début retourner(s^.frere) fin fonction pere(val s : sommetArbrePlanaire): sommetArbrePlanaire; début retourner(s^.pere) fin

136 Modification : fonction creerArbrePlanaire(val racine:objet):sommetArbrePlanaire; var tmp:^cellule; début new(tmp); tmp^.info=racine; tmp^.premierFils=NIL; tmp^.frere=NIL; tmp^.pere=NIL; retourner(tmp) fin

137 Modification : fonction detruireArbrePlanaire(ref s:sommetArbrePlanaire):vide; var tmp,f: sommetArbrePlanaire; début f= premierFils(s); tant que f!=NIL faire detruireArbrePlanaire(f); f=frere(f); fintantque supprimerSommet(s) fin

138 fonction ajouterFils(ref s:sommetArbrePlanaire,val x:objet):vide; /* ajoute un fils comme cadet cette fonction n'est pas en O(1) */ var tmp:^celluleAP; début new(tmp); tmp^.info=x; tmp^.frere=NIL; tmp^.pere=s; tmp^.premierFils=NIL si s^.premierFils==NIL alors s^.premierFils=tmp; sinon r=premierFils(s); tantque frere(r)!=NIL faire r=frere(r) fintantque r^.frere=tmp fin

139 fonction supprimerSommet(ref s:sommetArbrePlanaire):vide; /* le sommet doit être une feuille */ var p,r,tmp:^celluleAP; début r=premierFils(pere(s)); si r==s alors p=pere(s); p^.premierFils=s^.frere; sinon tantque frere(r)!=s faire r=frere(r); fintantque r^.frere=s^.frere; finsi delete(s) fin

140  Arbre binaire de recherche  Modification d'un arbre binaire de recherche  Equilibrage

141

142 fonction recherche(val x:sommet, val e:objet):sommet; var tmp:objet; debut si x==NIL alors retourner(NIL) sinon tmp= getValeur(x); si tmp==e alors retourner(x); sinon si e <=tmp alors retourner(recherche(filsGauche(x),e)); sinon retourner(recherche(filsDroit(x),e)); finsi fin Complexité minimum : maximum :

143 fonction recherche(val x:sommet, val e:objet):sommet; var tmp:objet; debut si x==NIL alors retourner(NIL) sinon tmp= getValeur(x); si tmp==e alors retourner(x); sinon si e <=tmp alors retourner(recherche(filsGauche(x),e)); sinon retourner(recherche(filsDroit(x),e)); finsi fin Complexité minimum : maximum :

144 fonction cherchePlusPetit(val x:sommet):sommet; debut tantque filsGauche(x)!=NIL faire x=filsGauche(x); fintantque retourner(x); fin Complexité minimum : maximum :

145 Dans l’ordre croissant, où se trouve le suivant d’un élément x dans un ABR ? 6 2 348271810 14 320 5

146 Complexité minimum : maximum : fonction chercheSuivant(val x: sommet, val e : objet):sommet; var p:sommet; debut x=cherche(x,e); si x==NIL alors retourner(NIL); sinon si filsDroit(x)!=NIL alors return(cherchePlusPetit(filsDroit(x)) sinon p=pere(x); tantque p!=NIL faire si filsGauche(p)==x alors retourner(p) sinon x=p; p=pere(p); finsi fintantque retourner(NIL); finsi fin

147 Les primitives ajouter et supprimer des objets permettent de faire évoluer un ABR.ajouter supprimer fonction ajouter(ref x:sommet, val e:objet):vide; var s:sommet; debut si e <= valeurSommet(x) alors s=filsGauche(x); si s==NIL alors ajouterFilsGauche(x,e); sinon ajouter(s,e); finsi Complexité minimum : maximum : sinon s=filsDroit(x); si s==NIL alors ajouterFilsDroit(x,e); sinon ajouter(s,e); finsi fin

148 fonction supprimer(ref x:sommet):vide; /*Tous les elts sont différents */ var p,f,y:sommet; debut si estFeuille(x) alors p=pere(x); /*traiter le cas racine*/ si filsGauche(p)==x alors supprimerFilsGauche(p) sinon supprimerFilsDroit(p) finsi Complexité minimum : maximum : sinon f=filsDroit(x); si f!=NIL y=cherchePlusPetit(f); sinon f=filsGauche(x); y=cherchePlusGrand(f); finsi var v : valElement; v=getValeur(y); supprimer(y); setValeur(x,v); finsi fin

149 Dans le cas général la fonction supprimer applique l’algorithme suivant : Si le sommet à supprimer :  est une feuille on l'enlève  a 1 fils on le remplace par son fils  a 2 fils on remplace sa valeur par la valeur précédente dans l’ordre croissant et on supprime le sommet qui portait cette valeur dans l’ABR.

150 La complexité des opérations sur un ABR dépendant de la hauteur de l'arbre, il est important qu'un ABR reste aussi proche que possible d'un arbre binaire parfait de manière à ce que la hauteur soit minimum. L'équilibrage d'un ABR peut-être obtenu par un algorithme de type "diviser pour régner". On récupère la liste des éléments triés dans un tableau T[1..N] où N est la taille de l'arbre de départ et on reconstruit l'arbre.

151 fonction lister(val x:sommet, ref T:tableau[1..N] d'objet, ref i:entier):vide debut si estFeuille(x)alors i=i+1; T[i]= getValeur(x); sinon si filsGauche(x)!=NIL alors lister(filsGauche(x),T,i); finsi i=i+1; T[i]= getValeur(x); si filsDroit(x)!=NIL alors lister(filsDroit(x),T,i); finsi fin

152 L'appel : liste(A,T,0) fournit, en utilisant l'ordre infixe, dans le tableau T la liste des valeurs dans l'ordre croissant de l'arbre A. fonction detruireArbreBinaire(ref A:arbreBinaire d'objet):vide; debut si s!=NIL alors detruireArbreBinaire(filsGauche(s)); supprimerFilsGauche(s); detruireArbreBinaire(filsDroit(s)); supprimerFilsDroit(s); finsi fin

153 fonction equilibre(ref A:arbreBinaire de objet):vide; var N:entier; var T:tableau[1..N]d'objet; debut N=tailleArbre(A); lister(A,T,0); detruireArbreBinaire(A); delete(A); A=construire(T,1,N)) fin

154 fonction construire(ref T:tableau[1..N]d'objet,ref d,f:entier):sommet; var m:entier; var c,s:sommet ; debut si d≤f alors m=(d+f)//2; new(c); setValeur(c,T[m]); si d==f alors c^.gauche=NIL; c^.droit=NIL; retourner(c); sinon s=construire(d,m-1); c^.gauche=s; si s!=NIL alors s^.pere=c; finsi s=construire(m+1,f); c^.droit=s si s!=NIL alors s^.pere=c; finsi retourner(c); sinon retourner(NIL) finsi fin

155  Définition  Ajouter et supprimer dans un tas Max  Implémentation  Files de priorité

156 Définition 6.1 : Un tas max (resp.tas min) T est un arbre binaire quasi-parfait étiqueté par des objets comparables (ie : il existe un ordre total) tel que tout nœud a une étiquette plus grande ou égale (resp. plus petite) que ses fils. Propriété 6.1 : La hauteur d'un tas est O(log(n)). L’ajout d’un élément se fait en conservant la structure ABQP

157 Un tas est un containeur et un arbre binaire, il dispose donc des primitives des arbres binaires ainsi que ceux d'un containeur : fonction valeur(ref T:tas d'objet): objet; // renvoie l'objet stocké à la racine de l'arbre fonction ajouter(ref T:tas de objet, val v:objet):vide; // ajoute l'objet dans le tas fonction supprimer(val T:tas de objet):vide; // suppression de la racine et tassement de l'arbre fonction creerTas(ref T:tas,val:v:objet):vide; fonction detruireTas(ref T:tas):vide;

158 Pour ajouter une valeur v dans un tas, on crée une nouvelle feuille dans l'arbre quasi-parfait en lui affectant la valeur v.  Soit (r=s 0,...,s k ) le chemin de la racine à cette nouvelle feuille.  Pour i allant de k à 1 si la valeur stockée dans s i est plus grande que celle stockée dans s i-1 alors on échange ces valeurs. On fait une réorganisation montante : un exemple est iciici

159 Dans un tas supprimer un élément consiste toujours à supprimer la racine. Pour supprimer la valeur dans un tas, on remplace la valeur de la racine par la valeur v de la dernière feuille de l'arbre.  On supprime cette feuille.  On fait descendre la valeur v dans l'arbre par échange avec la valeur la plus grande d'un des fils si celle ci est plus grande. On fait une réorganisation descendante : un exemple est iciici

160 On utilise la numérotation des nœuds dans le parcours hiérarchique d’un AB. La racine est numérotée 1. Le fils gauche de la cellule numéro i a pour numéro 2*i Le fils droit de la cellule numéro i a pour numéro 2*i +1 1 2 3 7654

161 6 2 108277 9 320 5 123456789101112131415161718192021 8692270107325

162 On utilise cette propriété pour représenter un tas dans un tableau. De plus dans les opérations d'ajout et suppression des valeurs, on devra pouvoir parcourir l'arbre. Un curseur sera donc utile. tas=structure arbre:tableau[1..tailleStock] d'objet; tailleTas:entier; finstructure; curseur=entier; sommet=entier; De ce fait, les primitives arbre binaire prennent comme paramètre un tas et non un sommet.

163 Les fonction ajouter et supprimer sont spécifiques au tas.  accès fonction getValeur(ref T:tas d'objet; Val s:sommet):objet; debut retourner(T.arbre[s]); fin; fonction valeur(ref T:tas d'objet):objet; debut retourner(T.arbre[1]); fin fonction filsGauche(val s:sommet):sommet; debut retourner(2*s); fin

164 Les fonction ajouter et supprimer sont spécifiques au tas.  accès fonction filsDroit(val s:sommet):sommet; debut retourner(2*s+1); fin fonction pere(val s:sommet):sommet; debut retourner(partieEntiere(s/2)); fin fonction tasPlein(ref T:tas d'objet):booleen; debut retourner(T.tailleTas==tailleStock) fin

165  modification fonction setValeur(ref T:tas d'objet; val s:sommet; val x:objet):vide; debut T.arbre[s]=x; fin fonction creerTas(ref T:tas d'objet; val x:objet):vide; debut T.arbre[1]=x; T.tailleTas=1; fin

166  Gestion du tas fonction ajouter(ref T:tas d'objet, val v:entier):vide debut T.tailleTas=T.tailleTas+1; T.arbre[T.tailleTas]=v; reorganiseTasMontant(T,tailleTas); fin

167  Gestion du tas fonction reorganiseTasMontant(ref T: tas d'objet; val x:sommet):vide; var p:sommet; var signal:booléen; debut p=pere(x); signal=vrai; tantque x!=1 et signal faire si getValeur(T,x)>getValeur(T,p) alors échanger(T.arbre[p],T.arbre[x]) x=p; p=pere(x); sinon signal=faux finsi fintantque fin

168  Gestion du tas fonction supprimer(ref T:tas d'objet):vide; var r:objet; debut T.arbre[1]=T.arbre[T.tailleTas]; T.tailleTas=T.tailleTas-1; reorganiseTasDesc(T,1); fin

169  Gestion du tas fonction reorganiseTasDesc(ref T:tas d'objet, val x:sommet):vide; var g,d:sommet; debut g= filsGauche(x); d= filsDroit(x); si g!=NIL alors si d!=NIL alors si getValeur(T,d)>getValeur(T,g) alors g=d; finsi; finsi si getValeur(T,x)<getValeur(T,g) alors échanger(T.arbre[x],T.arbre[g]); reorganiseTasDesc(T,g) finsi fin

170 Définition 6.2 : Une file de priorité est un tas dans lequel on a la possibilité de modifier les valeurs des sommets. On dispose donc d'une primitive supplémentaire : fonction changeValeur(ref T:tas d'objet, val s:sommet, val v:objet):vide; debut setValeur(T,s,v); si v > getValeur(T,pere(s)) alors reorganiseTasMontant(T,s) sinon si v < getValeur(T,filsDroit(s)) ou v < getValeur(T,filsGauche(s)) alors reorganiseTasDesc(T,s) finsi fin Complexité :

171  Définitions  Fonction de hachage  Adressage chainé  Adressage ouvert  Réorganisation d'une table de hachage

172 Soient a et b deux entiers. Soient q et r respectivement leur quotient et reste dans la division Euclidienne, on a : a=b*q + r. On dit que a est égal à r modulo b et on écrira a=r[b].

173 Définition 7.1 : Soit K un ensemble de valeurs et m un entier naturel, une fonction de hachage h m est une fonction définie de K dans {0,...,m-1}. h m : K {0,...,m-1}  Les éléments de K sont appelées clés.  Si k est une clé, h(k) est dite valeur de hachage de k.

174 Définition 7.2 : Soit m un entier naturel et h m une fonction de hachage, une table de hachage est un containeur tel que :  le nombre d'éléments de la table (dimension ou taille) est fixe,  l'accès aux éléments s'effectue indirectement par la valeur de hachage de la clé.

175  Exemple 0 1 2 … kiki m-1 K kiki k0k0 kjkj h m (k i ) Table de hachage

176 Remarques  Les tables de hachage sont très utiles dans le cas où l'amplitude des clés est grande (structure de tableau non utilisable) et les éléments à gérer sont "assez figés" ce qui permet d'espérer un temps d'accès à l'information proche de O(1) (structure de liste trop pénalisante).  Pour une séquence d'élément, il est clair qu'il peut exister deux clés k 1 et k 2 de K telles que h m (k 1 )=h m (k 2 ), on dit alors qu'il y a collision des clés k 1 et k 2.  Soit p dans [0..m-1], il est possible qu'il n'existe pas de clé k dans K telle que h m (k)=p.

177  La structure de données pour représenter une table de hachage est un tableau de dimension [0..m-1]. Pour une clé k de K, T[h m (k)] donne l'accès à l'élément de clé k.  Plus qu'à la clé elle-même le plus souvent on souhaite accéder aux informations associées à la clé. La clé est donc stockée ainsi que l'adresse permettant d'accéder aux informations.  On précisera ces moyens d'accès aux paragraphes concernant la gestion des collisions : adressage chainé, adressage ouvert.

178  On nommera le type abstrait tableHash.  La valeur de hachage d'une clé est un curseur. Les primitives d'accès à une table de hachage sont :  accès fonction chercher(ref T:tableHash_de_cle, val v:cle):curseur;  modification fonction creerTablehachage(ref T: tableHash_de_cle, ref h:fonction):vide; fonction ajouter(ref T:tableHash de cle, val x:cle):booleen; fonction supprimer(ref T:tableHash de cle, val :cle):vide; fonction detruireTablehachage(ref T:tableHash de cle): vide; Elles sont définies en fonction de h m et du mode de gestion des collisions.

179

180

181 Famille de hachage universel Définition 7.3 : Soit H un ensemble de fonction de hachage de U dans [0..m[. On dit que la famille H est universelle si pour toutes clés k 1, k 2 dans U, le nombre de fonctions h de H telles que h(k 1 )=h(k 2 ) est égal à card(H)/m. Probabilité de collision : 1/m

182

183 Définition 7.4 : L'adressage d'une table de hachage est dit chainé si l'élément i du tableau donne accès à une structure de données permettant de stocker les clés k telles que h m (k)=i. Les valeurs sont donc stockées à l'extérieur de la table qui est un tableau de pointeurs. Par suite, si il n'existe pas de clé k telle que h m (k)=i alors T[i]=NIL. L'espace de stockage des clés peut être une liste doublement chainée. On a dans ce cas tableHash de clé=structure table:tableau[0..m-1] de listeDC de clé; h:fonction(val v:clé):entier finstructure

184 Primitives d’accès : fonction chercher(ref T:tableHash_de_cle, val e:entier):curseur; debut retourner(chercherListe(T.table[T.h(e)],e)) fin

185 Primitives de modification : fonction creerTableHach(ref T: tableHash_de_cle, ref h:fonction):vide; var i:entier; debut pour i allant de 0 à m-1 faire creerListe(T.table[i]) finpour T.h=h; fin fonction ajouter(ref T:tableHash_de_cle,val e:entier):booleen; debut insererEnTete(T.table[T.h(e)],e); retourner(vrai): fin

186 Primitives de modification : fonction supprimer(ref T:tableHash_de_cle;val e:entier):vide; debut supprimer(T.table[T.h(e)],e)) fin Théorème 7.2 : Dans une table de hachage à adressage chainé, une recherche fructueuse ou infructueuse prend en moyenne O(1+n/m) si chaque élément à les mêmes chances d'être haché vers l'une quelconque des cases indépendamment des autres éléments (hachage uniforme).

187 Définition 7.5 : L'adressage d'une table de hachage est dit ouvert si les éléments du tableau sont les clés elles mêmes. Les éléments de la table sont donc initialisés à NULL. La gestion de la collision se fait en trouvant une place libre dans la table. Pour cela on utilise une seconde fonction s(x,i) à valeur dans [0..m] que l'on compose avec h m (k).

188 Cette seconde fonction dite de sondage doit vérifier les propriétés suivantes :  s(h m (k),0)=h m (k)  s(h m (k),i)) i=0…m-1 est une permutation de la séquence (i) i=0…m-1 La méthode d'insertion consiste, en cas de collision pour une clé k, à sonder les places disponibles s(h m (k),i) à partir de i=0 jusqu'à m-1. Si au bout de m sondages, aucune place disponible n'a été détectée, la table est dite saturée.

189

190 L'espace de stockage des clés est alors un tableau. On a dans ce cas : tableHash_de_cle=structure table:tableau[0..m-1] de cle; h : fonction(val v : cle) : entier s : fonction(val v : cle; val i : entier) : entier finstructure

191 Primitives d’accès : fonction chercher(ref T:tableHash_de_cle, val e:entier):curseur; var i:entier; debut i=0; tant que T.table[T.s(T.h(e),i)]!=e et i<m faire i=i+1 fintantque si i==m alors retourner(NULL) sinon retourner(i) finsi fin

192 Primitives de modification fonction creerTablehachage(ref T: tableHash_de_cle, ref h : fonction(var x:entier):entier), ref s : fonction(var x:entier):entier):vide; var i:entier; debut pour i allant de 0 à m-1 faire T.table[i]=NULL; finpour T.h=h; T.s=s; fin

193 Primitives de modification fonction ajouter(ref T:tableHash_de_cle, val e :entier):booleen; var i:entier; debut i=0; tant que T.table[T.s(T.h(e),i)]!=NULL et i<m faire i=i+1 fintantque si i==m alors retourner(faux) sinon T.table[T.s(T.h(e),i)]=e; retourner(vrai) finsi fin

194 Primitives de modification fonction supprimer(ref T:tableHash_de_cle, val e:entier):vide; var p:curseur; debut p=chercher(T,e); T.table[p]=NULL fin

195 Théorème 7.3 : Etant donné une table de hachage de facteur de remplissage r, une recherche infructueuse ou l'insertion d'une clé se fait en moyenne en 1/(1-r), si chaque élément a les mêmes chances d'être haché vers l'une quelconque des cases indépendamment des autres éléments (hachage uniforme ). Théorème 7.4 : Etant donné une table de hachage de facteur de remplissage r, une recherche fructueuse se fait en moyenne en (1/r)*ln(1/(1-r)), si chaque élément a les mêmes chances d'être haché vers l'une quelconque des cases indépendamment des autres éléments (hachage uniforme ).

196 Le taux d'occupation de la table doit rester relativement faible pour minimiser le risque de collision sinon le nombre de collision augmente et la performance se dégrade. Ceci veut dire qu'on ajoute à chaque type abstrait un champ "taux de remplissage" égal au rapport du nombre d'éléments divisé par la taille de la table. Dès que ce taux dépasse un seuil fixé, la fonction "ajouter" effectue automatiquement l'appel à la fonction de redimensionnement de la table.

197  Définition  Implémentation  Opérations d'ajout et suppression

198  Un dictionnaire est une structure de donnée permettant de stocker des mots.  Dans ce cours, on considère que le mot est stocké dans une variable de type "mot" dont on peut connaitre la longueur par la fonction "longueur". fonction longueur(ref M:mot):entier;  Si M est un mot, M[i] est le i ème caractère de M.

199  Un dictionnaire est donc un containeur dont les primitives sont les suivantes. accès : fonction appartient((ref d:dictionnaire,val M::mot):booléen; modification : fonction creerDictionnaire(ref d: dictionnaire):vide fonction ajouter(ref d:dictionnaire,val M::mot):vide; fonction supprimer(ref d:dictionnaire,val M:mot):vide; fonction detruireDictionnaire(ref d:dictionnaire):vide;

200 On considère que l'implémentation se fait dans le type arbreBinaire. On munit le dictionnaire d'un curseur de façon à ne pas passer ou déclarer un pointeur à chaque appel. type dico=structure a:sommet; /* l'arbre*/ p:sommet; :* le curseur */ finstructure Le principe est le suivant :  Descendre sur le fils gauche correspond à passer à la lettre suivante dans un mot,  Descendre sur le fils droit correspond à passer à une autre lettre en même position.  Tous les mots se terminent par un même caractère que nous noterons "\0" et qui est stocké dans l'arbre.

201 c a s \0 i r e r e e r e i r e m e

202 Pour ajouter un mot M dans un dictionnaire :  on recherche le plus long préfixe du mot M contenu dans l'arbre à partir de la racine, on détermine ainsi un sommet S de l'arbre correspondant au i premières lettres du mot.  On parcourt à partir de S la branche droite de l'arbre de manière à trouver deux sommets tels que : ◦ S2==filsDroit(S1), ◦ valeur(S1)<M[i+1]<valeur(S2)  On crée un arbre "baguette" (tous les fils droits sont vide) B étiqueté par toutes lettres de M à partir du (i+1) ème caractère.  on insère B entre les sommets S1 et S2 dans l'arbre  Un exemple est iciici

203 Pour supprimer un mot M dans un dictionnaire :  on recherche la feuille correspondante au mot, elle se trouve au bout d'un arbre "baguette" B,  on détruit l'arbre B.  Un exemple est iciici

204 fonction chercher_branche_droite(ref d : dico; ref c:car): booleen; var v: car; debut v=valeur(d.p) tant que filsDroit(d.p)<>NIL et v<c faire d.p=filsDroit(d.p) v= valeur(d.p) fintantque si v==c alors /*d.p est positionné sur la lettre c*/ retourner VRAI sinon si filsGauche(pere(d.p))!=d.p et filsDroit(d.p)<>NIL alors d.p=pere(d.p) finsi /* dans le cas ou d.p est le premier de la branche droite le sommet contient une valeur >C */ /* sinon d.p est sur l'elt précédant la place possible pour un ajout à droite */ retourner FAUX finsi fin

205 fonction prefixe(ref d: dico; ref M:Mot;ref i:entier) :booleen; /*->VRAI M est dans le dico*/ /*->FAUX M[i] est la dernière lettre du prefixe dans le dico debut cas où cas M[i]=="\0" et valeur(d.p)=="\0" : /*le mot existe dans le dico*/ retourner VRAI cas M[i]==valeur(d.p) /* filsGauche(d.p)!=NIL nécessairement*/ d.p=filsGauche(d.p) i=i+1 /* On continue à chercher le préfixe /* retourner(prefixe(d,M,i)) cas chercher_branche_droite(d,M[i]) alors /*d.p est sur le caractère correspondant à M[i] dans dico on*/ /*repart de là prefixe se charge de descendre à gauche*/ retourner(prefixe(d,M,i)) autre cas : /* on a le prefixe max au i-1eme caractère. d.p est sur l'elt /*précédant la place possible*/ i=i-1 retourner FAUX fincasou fin

206 fonction creer_arbre_baguette(ref M:mot;val i:entier):sommet; var s,tmp,c:sommet var j:entier; debut s=creerArbreBinaire(M[i]); tmp=s; pour j=i+1 a longueur(M) faire ajouterFilsGauche(tmp,M[j]); tmp=filsGauche(tmp) finpour retourner(s) fin

207 fonction ajouter(ref d:dico,ref M:mot):vide debut d.p=d.a i=1 si !prefixe(d,M,i) alors s=creer_arbre_baguette(M, i+1) cas où : cas i=0 et pere(d.p)==NIL : /* cas de la racine*/ s^.droit=d.a s^.pere=nil d.a^.pere=s d.a=s cas M[i]>valeur(d.p) : /* insertion en milieu de branche droite */ s^.droit=d.p^.droit s^.pere=d.p si filsDroit(d.p)!=NIL alors /* !fin de branche droite */ s^.droit^.pere=s finsi d.p^.droit=s autre cas s^.droit=d.p; s^.pere=d.p^.pere; d.p^.pere=s; s^.pere^.gauche==s fincasou fin

208  Arbre AVL  Facteur d'équilibrage et rotation  Implémentation

209 Définition :  Un arbre AVL est un arbre binaire éventuellement vide tel que la différence de hauteur entre le sous arbre gauche et le sous arbre droit d'un nœud diffère d'au plus 1.  les arbres gauches et droits d'un sommet sont des arbres AVL Le nom AVL vient du nom des auteurs G.M. Adelson-Velsky et E.M.Landis (1982 ). Propriété : Si n est le nombre de nœuds d'un arbre AVL alors sa hauteur est log 2 (n)

210 Chaque nœud contient un entier appelé facteur d'équilibrage qui permet de déterminer si il est nécessaire de rééquilibrer l'arbre. Définition : Soit s un sommet ayant pour sous arbre gauche (resp. droit) G s (resp. D s ). Le facteur d'équilibrage eq(s) du sommet s est défini par : eq(s)= h(D s )-h(G s ) avec h(NIL)=0 et si A est un arbre h(A)=hauteur(A)+1. Le facteur d'équilibrage d'un nœud d'un arbre AVL vaut 0,1 ou -1. Lors d'insertion ou suppression, l'arbre peut se déséquilibrer (valeur 2 ou -2), on utilise alors des rotations pour rééquilibrer l'arbre.

211 Définition : Une rotation droite autour du sommet y d'un arbre binaire de recherche consiste à faire descendre le sommet y et à faire remonter son fils gauche x sans invalider l'ordre des éléments. L'opération inverse s'appelle rotation gauche autour du sommet x.

212 Dans la rotation seuls les facteur d'équilibrage de X et Y sont modifiés. Notons eq'(X) et eq'(Y) les facteurs d'équilibrage après rotation. Propriété : Après une rotation droite autour du sommet Y, on a : eq'(X)=eq(X)+1+max(eq'(Y),0) eq'(Y)=eq(Y)+1-min(eq(X),0) Propriété : Après une rotation gauche autour du sommet X, on a : eq'(X)=eq(X)-1-max(eq(Y),0) eq'(Y)=eq(Y)-1+min(eq'(X),0)

213 Les opérations d'insertion et suppression sont celles d'un arbre binaire de recherche dans lesquelles on ajoute la gestion du facteur d'équilibrage. Insertion : L'insertion aboutit à la création d'une feuille f. Considérons le premier ancêtre y de cette feuille qui viole la condition AVL, on a eq(y)=-2 ou eq(y)=2 et ces deux cas sont symétriques. Supposons que eq(y)=-2 et soit x le fils gauche de y. On a deux cas.  soit eq(x)=-1 ou 0, on effectue une rotation droite,

214  soit eq(x)=1, alors x a un sous arbre droit de racine z, qui a deux sous arbres. On effectue une rotation gauche autour de x puis une rotation droite autour de y.

215  La suppression aboutit à la suppression d'une feuille.  Considérons le premier ancêtre y de cette feuille qui viole la condition AVL, on a : eq(y)=-2 ou eq(y)=2 et ces deux cas sont symétriques. Supposons que eq(y)=-2 Soit x le fils gauche de y et t le fils droit de y. La feuille a été supprimée dans le sous arbre de racine t. On a trois cas : soit eq(x)=-1, on effectue une rotation droite,

216  soit eq(x)=0, on effectue aussi une rotation droite,

217  soit eq(x)=1, alors x a un sous arbre droit de racine z, qui a deux sous arbres.

218  On effectue une rotation gauche autour de x puis une rotation droite autour de y.

219  La hauteur du nouveau sous arbre a même hauteur que le sous arbre de départ si le facteur d'équilibrage de la racine est 0.  Dans ce cas, il suffit donc d'une opération d'équilibrage pour que l'arbre soit AVL.  Dans les autres cas il faut recommencer la même opération en remontant dans l'arbre.  Le cas eq(y)=2 est obtenue par symétrie.  Figures complètes iciici

220 L'intérêt du facteur d'équilibrage est que cette information nécessite 2 bits. Néanmoins les algorithmes permettant la gestion de eq sont délicats. Dans la suite, une cellule pour un arbre AVL doit contenir un champ supplémentaire qui est la hauteur. type celluleAVL=structure info:objet; hauteur:entier; gauche:sommet; droit:sommet; père:sommet; finstructure sommetAVL=^celluleAVL; On accède à ce nouveau champ par les deux primitives suivantes : fonction getHauteur(ref S:sommet):entier; /* 1 pour une feuille; 0 si NIL/* fonction setHauteur(ref S:sommet; val h:entier):entier; /* 1 pour une feuille; 0 si NIL/*

221 Les fonctions implémentant les rotations sont immédiates. fonction rotationDroite(ref y:sommet):vide; var x,p:sommet; debut x=filsGauche(y); p=pere(y); si p!=NIL alors si y=filsGauche(p) alors p^.gauche=x; sinon p^.droit=x; finsi x^.pere=p; y^.pere=x; y^.gauche=x^.droit; x^.droit=y; setHauteur(y,max(getHauteur(filGauche(y)),getHauteur(filsDroit(y)))+1); setHauteur(x,max(getHauteur(filGauche(x)),getHauteur(filsDroit(x)))+1); fin

222 Les fonctions implémentant les rotations sont immédiates. fonction rotationGauche(ref x:sommet):vide; var y,p:sommet; début y=filsDroit(x); p=pere(x); si p!=NIL alors si x=filsGauche(p) alors p^.gauche=y; sinon p^.droit=y; finsi y^.pere=p; x^.pere=y; x^.droit=y^.gauche; y^.gauche=x; setHauteur(x,max(getHauteur(filGauche(x)),getHauteur(filsDroit(x)))+1); setHauteur(y,max(getHauteur(filGauche(y)),getHauteur(filsDroit(y)))+1); fin

223 Les fonctions d'insertion et suppression doivent prendre en compte le calcul du facteur d'équilibrage ainsi que le maintien de cet équilibre. fonction ajouter(ref x:sommet, val e:objet):vide; var s:sommet; début si e ≤ getValeur(x) alors s=filsGauche(x); si s==NIL alors ajouterFilsGauche(x,e); setHauteur(filsGauche(x),1) equilibreAprèsInsertion(filsGauche(x)) sinon ajouter(s,e); finsi sinon s=filsDroit(x); si s==NIL alors ajouterFilsDroit(x,e); setHauteur(filsDroit(x),1); equilibreAprèsInsertion(filsDroit(x)) sinon ajouter(s,e); finsi fin

224 fonction supprimer(ref x:sommet):booléen; var p,f,y:sommet; début si estFeuille(x) alors p=pere(x); si filsGauche(p)==x alors supprimerFilsGauche(p) setHauteur(p,getHauteur(filsDroit(p)+1)) sinon supprimerFilsDroit(p) setHauteur(p,getHauteur(filsGauche(p)+1)) finsi equilibreAprèsSuppression(p) sinon f=filsDroit(x); si f!=NIL y=cherchePlusPetit(f); sinon f=filsGauche(x); y=cherchePlusGrand(f); finsi setValeur(x,getValeur(y)); supprimer(y); finsi fin

225 fonction equilibreAprèsInsertion(ref x:sommet):vide; var eq:entier; var s,p:sommet; debut eq=0; p=x; tantque pere(p)!=NIL et eq!=2 et eq!=2 faire s=p; p=pere(s); setHauteur(p,max(getHauteur(filGauche(p)),getHauteur(filsDroit(p)))+1); eq=getHauteur(filsDroit(p))-getHauteur(filsGauche(p)); fintantque si eq==2 ou eq==-2 alors equilibreUnSommet(p,s); finsi fin

226 fonction equilibreUnSommet(ref p,s:sommet):vide; début si s==filsGauche(p) alors si getEquilibre(p)==-2 alors si getEquilibre(s)<1 alors rotationDroite(p); sinon rotationGauche(s); rotationDroite(p); finsi sinon si getEquilibre(p)==2 alors si getEquilibre(s)>-1 alors rotationGauche(p) sinon rotationDroite(s); rotationGauche(p); finsi fin

227 Dans le cas de suppression, on remonte à partir de la feuille supprimée dans l'arbre et de la même manière on détecte les nœuds déséquilibrés. Il est possible que plusieurs rotations soient nécessaires. En effet un déséquilibre peut en entrainer un autre. fonction equilibreAprèsSuppression(ref x:sommet):vide; var eq:entier; var s,p:sommet; début eq=1; p=x; p=pere(s); tantque p!=NIL et eq!=0 faire s=p; p=pere(p); setHauteur(p,max(getHauteur(filGauche(p)),getHauteur(filsDroit(p)))+1); eq=getHauteur(filsDroit(p))-getHauteur(filsGauche(p)); equilibreUnSommet(p,s); fintantque fin

228  Définition  Liste simplement chainée  Quelques exemples d'algorithmes  Liste doublement chainée

229 Définition  Une liste est un containeur tel que le nombre d'objets (dimension ou taille) est variable,  L'accès aux objets se fait indirectement par le contenu d'une clé qui le localise de type curseur. Par exemple : curseur=^type_predefini; liste de type_predefini = curseur L NIL

230 Définition : Une liste est dite simplement chainée si les opérations suivantes s'effectuent en O(1). Accès fonction premier(ref L: Liste):curseur; fonction suivant(ref L: Liste; val P:curseur):curseur; fonction listeVide(ref L:Liste):booléen; Modification fonction creerliste(ref L:Liste):vide; fonction insererApres(ref L:Liste; val x:objet; ref P:curseur):vide; fonction insererEnTete(ref L:Liste; val x:objet):vide; fonction supprimerApres(ref L:Liste; val P:curseur):vide; fonction supprimerEnTete(ref L:Liste):vide;

231 Test de fin de liste fonction estDernier(ref L:Liste; ref P:curseur):booléen; début retourner(suivant(L,P)=NIL) fin Complexité: O(1).

232 Chercher un élément dans une liste fonction chercher(ref L: Liste; ref E:objet):curseur; var p: curseur; début si listeVide(L) alors retourner(NIL) sinon p=premier(L); tant que non(estDernier(L,p)) et (contenu(p)!=e) faire p=suivant(L,p); fintantque si (contenu(p)!=e) alors retourner(NIL) sinon retourner(p) finsi fin Complexité: O(n).

233 Chercher un élément dans une liste fonction chercher(ref L: Liste; ref E:objet):curseur; var p: curseur; début si listeVide(L) alors retourner(NIL) si contenu(L)==E alors retourner(L) chercher(suivant(L,premier(L)),E) Complexité: O(n).

234 Trouver le dernier élément fonction trouverDernier(ref L:liste):curseur; var p: curseur; debut si listeVide(L) alors retourner(NIL) sinon p=premier(L); tant que non(estDernier(L,p)) faire p=suivant(L,p); fintantque retourner(p) finsi fin Complexité: O(n).

235 Trouver le dernier élément fonction trouverDernier(ref L:liste):curseur; var p: curseur; debut si listeVide(L) alors retourner(NIL) finsi p=premier(L); si(estDernier(L,p)) retourner(p) finsi trouverDernier(suivant(L,p)) fin Complexité: O(n).

236 Calculer la taille d’une liste fonction taille(val L:Liste):entier; var p;curseur; var t:entier; debut si listeVide(L) alors retourner(0) sinon retourner(1+taille(suivant(L,premier(L)))) finsi fin finfonction Complexité: O(n).

237 Insérer dans une liste triée On suppose la liste triée dans l'ordre croissant fonction insertionTrie(ref L:liste; val e: objet):vide; var p:curseur; début si listeVide(L) alors insererEnTete(L,e) sinon si contenu(premier(L))>e alors insererEnTete(L,e) sinon insererTrie(suivant(L,premier(L)),e) finsi fin Complexité: O(n).

238 Décrire l’algorithme pour supprimer un objet e dans une liste L.

239 Définition : Une liste doublement chainée est une liste pour laquelle les opérations en temps O(1) sont celles des listes simplement chainées auxquelles on ajoute les fonctions d'accès fonction dernier(val L:Liste_DC):curseur; fonction precedent(val L:ListeDC; val P:curseur):curseur;


Télécharger ppt "Année 2014-2015 Carole Blanc.  Carole Blanc :  Site WEB :"

Présentations similaires


Annonces Google