IFT-2000: Structures de Données

Slides:



Advertisements
Présentations similaires
ORTHOGRAM PM 3 ou 4 Ecrire: « a » ou « à » Référentiel page 6
Advertisements

Module Systèmes d’exploitation
Structures de données avancées : Principales structures de données
A l’issue des conseils de classe de 3ème,
Tris.
Chapitre 3 Les arbres binaires
Chapitre annexe. Récursivité
Licence pro MPCQ : Cours
Classification et prédiction
Fonctions & procédures
LES TRIANGLES 1. Définitions 2. Constructions 3. Propriétés.
Chapitre 3 (fin). Les arbres AVL
Par Clément en vacances sur la Côte d’Azur Le 17 décembre 2011
Cours 8 Arbres équilibrés
Récursivité.
LOGO Responsable du cours Mlle Amina GHRAB : 1 ère année IAG Institut Supérieur de Gestion de Tunis.
Les structures de données arborescentes
Cours de physique générale I Ph 11
RECURSIVITE ARBRES BINAIRES
Détection de co-évolution de gènes Master 2 : Informatique à Finalité Professionnelle et Recherche Unifiée (IFPRU) Parcours Ingénierie de lIntelligence.
Arbre Rouge Noir.
IFT-2000: Structures de Données Introduction à lanalyse dalgorithmes Dominic Genest, 2009.
IFT-2000: Structures de Données Listes chaînées Dominic Genest, 2009.
Bases de données lexicales
Tableaux de distributions
Tableaux de distributions
Gestion de Fichiers Arbres B.
1.3 COORDONNÉES DES POINTS
Systèmes d’équations du premier degré à deux variables
Les fichiers indexés (Les B-arbres)
LES ARBRES IUP 2 Génie Informatique
Algorithme de Bellman-Ford
IFT-2000: Structures de données
IFT-2000: Structures de données Les graphes Dominic Genest, 2009.
Arbres Rouge noir Démo : INF3105 Structures de données et algorithmes
Structures de données IFT-2000
Structures de données IFT-2000
RACINES CARREES Définition Développer avec la distributivité Produit 1
Représentation des systèmes dynamiques dans l’espace d’état
Représentation des systèmes dynamiques dans l’espace d’état
Programmation linéaire en nombres entiers Algorithme de la subdivision successive («Branch and Bound Algorithm»)
1.1 LES VECTEURS GÉOMÉTRIQUES
1 Licence dinformatique Algorithmique des graphes Problèmes dordonnancement. Utilisation de ce document strictement réservée aux étudiants de l IFSIC dans.
Les arbres binaires.
Les arbres et tas binomiaux
Arbres équilibrés Les transformation restructurantes dans leur ordre de définition: LL RR LR RL Facteur d’équilibre de noeud = (hauteur de s-arbre a gauche)
Exposé en structures de données
Inéquations du premier degré à une inconnue
IFT-2000: Structures de données Piles et files Dominic Genest, 2009.
IV. Arbres  Arbre binaire (AB) Représentation SDD d’un AB
Structures de données IFT-2000 Abder Alikacem La récursivité Semaine 5 Département dinformatique et de génie logiciel Édition Septembre 2009.
Les rotations Voici un autre exemple dajout. Celui-ci engendre un cas simple de déséquilibre, car larbre.
Structures de données IFT-2000
LES ARBRES Un arbre est une structure homogène dont chaque élément,
Structures de données IFT-2000 Abder Alikacem Semaine 11 Gestion des arbres binaires de tri et de recherche. Les arbres cousus. Les arbres n-aires Département.
Programmation linéaire en nombres entiers : les méthodes de troncature
Structures de données IFT-2000 Abder Alikacem La récursivité Département d’informatique et de génie logiciel Édition Septembre 2009.
Le langage C Structures de données
Structures de données avancées : Arbres Red-Black
LES PILES ET FILES.
Exercice de vérification 1 p
MIGO ET COMPLEXITE1 ARBRES EQUILIBRES Définition : On dit qu’un arbre binaire est H équilibré si en tout nœud de l’arbre, les hauteurs des sous-arbres.
Arbres binaires et tables de hachage
Exploration systématique de graphes
Structures de données IFT-2000
Structures de données IFT-2000 Abder Alikacem Semaine 10 Les algorithmes de recherche Les structures arborescentes Département d’informatique et de génie.
Arbres AVL - Hauteur d’un arbre AVL - Insertion et restructuration
4/25/2017 4:30 PM Arbres (2,4) CSI2510 CSI2510.
CSI25101 Tri Plus efficace. CSI25102 Tri récursif Le tri récursif divise les données de grande taille en deux presque moitiés et est appelé récursivement.
. Le B-Arbre.
Transcription de la présentation:

IFT-2000: Structures de Données Les arbres

Arbre Un arbre est une structure dans laquelle on a un nœud qui est une racine, puis chaque nœud a zéro, un ou plusieurs enfants. Les nœuds qui n’ont pas d’enfants sont appelées des feuilles. Racine Feuille Feuille Feuille Feuille

Arbre binaire Un arbre est dit binaire si chacun de ses nœuds comporte un maximum de deux enfants.

Arbre binaire de recherche Un arbre binaire est dit de recherche s’il respecte la règle suivante: Pour chaque nœud, tous ses descendants de gauche comportent des valeurs plus petites que lui, et tous ses descendants de droite comportent des valeurs plus grandes que lui. 25 12 40 33 57

Implémentation d’une recherche simple typedef struct nœud { float valeur; struct nœud *enfant_de_gauche; // 0 s’il n’y a pas d’enfant de gauche. struct nœud *enfant_de_droite; // 0 s’il n’y a pas d’enfant de droite. } Noeud; Bool est_present(const Nœud *racine, float nombre) }

Implémentation d’une fonction qui compte les noeuds typedef struct nœud { float valeur; struct nœud *enfant_de_gauche; // 0 s’il n’y a pas d’enfant de gauche. struct nœud *enfant_de_droite; // 0 s’il n’y a pas d’enfant de droite. } Noeud; int nb_noeuds(const Nœud *racine) }

Définitions La hauteur d’un arbre est le nombre de rangées qu’il comporte. 25 Hauteur: 3 12 40 33 57

Implémentation de la fonction hauteur typedef struct nœud { float valeur; struct nœud *enfant_de_gauche; // 0 s’il n’y a pas d’enfant de gauche. struct nœud *enfant_de_droite; // 0 s’il n’y a pas d’enfant de droite. } Noeud; int hauteur(const Nœud *racine) }

Structure pour l’arbre avec un point d’entrée typedef struct nœud { float valeur; struct nœud *enfant_de_gauche; // 0 s’il n’y a pas d’enfant de gauche. struct nœud *enfant_de_droite; // 0 s’il n’y a pas d’enfant de droite. } Noeud; typedef struct Nœud *racine; // 0 si l’arbre est vide. int nb_noeuds; // Ce champ est optionel, mais il permet d’accélérer les requêtes sur la taille. } Arbre; Int hauteur(const Nœud *racine) // … } int hauteur(const Arbre *arbre) return hauteur(arbre->racine);

Clé de recherche Une clé de recherche doit toujours être choisie, afin d’établir la relation d’ordre qui régit la position des nœuds. D’autres information peut être emmagasinée dans chaque nœud. Dans l’exemple ci-bas, la clé de recherche est le prénom, et l’information complémentaire est l’âge. La relation d’ordre utilisée pour déterminer la position relative des nœuds est la comparaison lexicographique (c’est-à-dire l’ordre alphabétique) des prénoms. Dominic 31 Claude 55 Jean 40 Françis 35 Nestor 5

Implémentation d’une recherche par clé typedef struct nœud { char prenom[100]; int age; struct nœud *enfant_de_gauche; // 0 s’il n’y a pas d’enfant de gauche. struct nœud *enfant_de_droite; // 0 s’il n’y a pas d’enfant de droite. } Noeud; int trouve_age(const Nœud *racine, const char *prenom) }

Ajout (non équilibré) typedef struct nœud { char prenom[100]; int age; struct nœud *enfant_de_gauche; // 0 s’il n’y a pas d’enfant de gauche. struct nœud *enfant_de_droite; // 0 s’il n’y a pas d’enfant de droite. } Noeud; Nœud *ajouter(Nœud *racine, const char *prenom, int age) }

Arbre binaire de recherche équilibré Un arbre binaire de recherche est dit équilibré (ou balancé) quand on lui impose un critère sur la position de ses nœuds, et que ce critère permet de maintenir une hauteur de l’ordre du logarithme du nombre de nœuds qu’il comporte. Arbre bien équilibré Arbre mal équilibré

Arbre binaire de recherche AVL Il existe deux façons bien connues d’équilibrer les arbres binaires de recherche: Les arbres AVL, et les arbres Rouge-Noir. Pour le cours de Structures de Données, nous ne nous attarderons qu’aux arbres AVL. Dans un arbre AVL, la règle de l’équilibre est la suivante: Pour chaque nœud, la hauteur de son sous-arbre de gauche et celle de son sous-arbre de droite doivent différer d’au maximum 1.

Équilibre AVL Bien équilibré selon la règle AVL 3 3 2 2 2 1 1 1 1 1 Bien équilibré selon la règle AVL Mal équilibré selon la règle AVL 4 4 3 2 3 1 1 2 1 2 1 1 1

Nœud critique Quand il y a un déséquilibre, le nœud le plus bas à partir duquel il y a une différence de 2 ou plus est appelé le nœud critique. Ici, le nœud critique du déséquilibre est la racine Mais ce n’est pas toujours le cas 4 3 1 2 1 1

Plusieurs nœuds critiques Il peut parfois y avoir plusieurs nœuds critiques. Dans ce cas, on s’occupe d’abord du plus bas de tous.

Maintien de l’équilibre Quand on implémente un arbre AVL, il faut maintenir son équilibre. Les déséquilibres surviennent soit lors d’un ajout, soit lors d’une suppression. Le ou les nœuds critiques engendrés, s’il y a lieu, sont toujours sur le chemin de l’ajout ou de la suppression. Nouveau noeud

Rééquilibrer un arbre déséquilibré Quand un déséquilibre apparaît, il faut remodeler la partie de l’arbre dont la racine est le nœud critique. Nouveau noeud

Les quatre cas de déséquilibre Il faut d’abord identifier le genre de déséquilibre auquel on a affaire. D’abord, il faut voir de quel côté l’arbre penche à partir du nœud critique. Dans le cas de l’exemple ci-bas, c’est vers la gauche. Nouveau noeud

Les quatre cas de déséquilibre L’enfant immédiat du nœud critique du côté vers lequel l’arbre penche s’appelle le nœud sous-critique. Nœud critique Nœud sous-critique Nouveau noeud

Les quatre cas de déséquilibre Puis il faut regarder de quel côté penche l’arbre à partir du nœud sous-critique. L’arbre sous-critique n’a pas besoin d’être déséquilibré pour qu’on considère qu’il penche. Une différence de 1 suffit pour identifier le cas (contrairement à la vérification qu’on faisait au départ pour vérifier s’il y avait déséquilibre). Dans l’exemple ci-bas, l’arbre sous-critique penche vers la droite. Nœud critique Nœud sous-critique Nouveau noeud

Les quatre cas de déséquilibre Nous avons donc, dans cet exemple-ci, un déséquilibre vers la gauche, avec un arbre sous-critique qui penche vers la droite. Quand le sens du déséquilibre principal est différent du sens dans lequel l’arbre sous-critique penche, alors deux rotations sont nécessaires. Nous appelons ça un zig-zag. Quand le sens du déséquilibre principal est le même que le sens dans lequel l’arbre sous-critique penche, ou bien que l’arbre sous-critique ne penche pas dutout, alors une seule rotation est nécessaire, et il s’agit d’un zig-zig. Dans notre exemple, nous aurons donc à faire deux rotations. Nœud critique Nœud sous-critique Nouveau noeud

Les rotations Quand nous nous retrouvons dans le cas où il faut faire deux rotations, la première sert finalement à faire pencher l’arbre sous-critique dans le même sens que l’arbre critique, de façon à nous retrouver dans le cas simple d’une seule rotation. Nœud critique Nœud sous-critique Nouveau noeud

Les rotations Première rotation (préparatoire à la deuxième). Nœud critique Nœud sous-critique Nouveau noeud

Les rotations Première rotation (préparatoire à la deuxième). Nœud critique Nouveau noeud

Les rotations Première rotation (préparatoire à la deuxième). Nœud critique Nouveau noeud

Les rotations Première rotation (préparatoire à la deuxième). Nœud critique Nouveau noeud

Les rotations Première rotation (préparatoire à la deuxième). Nœud critique Nouveau noeud

Les rotations Première rotation (préparatoire à la deuxième). Nœud critique Nouveau noeud

Ancien nœud sous-critique Les rotations La première rotation est terminée. Grâce à cette première rotation, nous avons retrouvé un cas de rotation simple, car l’arbre sous-critique penche maintenant dans le même sens que le déséquilibre au nœud critique. Nœud critique Nœud nouvellement sous-critique Nouveau noeud Ancien nœud sous-critique

Les rotations Deuxième rotation. Nœud critique Nouveau noeud

Les rotations Deuxième rotation. Nouveau noeud

Les rotations Deuxième rotation. Nouveau noeud

Les rotations Deuxième rotation. Nouveau noeud

Les rotations Deuxième rotation. Nouveau noeud

Les rotations Deuxième rotation. Nouveau noeud

Les rotations Deuxième rotation. Nouveau noeud

Les rotations Les deux rotations sont terminées, nous avons maintenant un arbre AVL équilibré. Nouveau noeud

Les rotations Voici un autre exemple d’ajout. Celui-ci engendre un cas simple de déséquilibre, car l’arbre sous-critique penche dans le même sens que le déséquilibre au nœud critique. Supposons que nous ajoutons un nœud avec la valeur de clé 40 à l’arbre ci-bas. 40 50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 40 <50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 40 <50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. <50 40 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 50 40 >25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 50 >25 70 40 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 50 25 70 40 >36 13 60 85 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 50 25 70 >36 13 60 85 40 28 8 17 45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 50 25 70 36 13 60 85 40 28 8 17 <45 55 64 90 26 38 48 62

Les rotations Ajout de 40. 50 25 70 36 13 60 85 28 8 17 <45 55 64 90 40 26 38 48 62

Les rotations Ajout de 40. 50 25 70 36 13 60 85 28 8 17 45 55 64 90 40 26 >38 48 62

Les rotations Ajout de 40. 50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 >38 48 62 40

Les rotations La position du nouveau nœud 40 a été déterminée. On doit donc, en remontant, vérifier si l’arbre est déséquilibré. 50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62 40

Les rotations On vérifie l’équilibre nœud par nœud, en remontant le long du chemin parcouru depuis la racine. 50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62 1 40

Les rotations On vérifie l’équilibre nœud par nœud, en remontant le long du chemin parcouru depuis la racine. 50 25 70 36 13 60 85 28 8 17 45 55 64 90 2 1 26 38 48 62 40

Les rotations On vérifie l’équilibre nœud par nœud, en remontant le long du chemin parcouru depuis la racine. 50 25 70 36 13 60 85 2 3 28 8 17 45 55 64 90 26 38 48 62 40

Les rotations On vérifie l’équilibre nœud par nœud, en remontant le long du chemin parcouru depuis la racine. Un déséquilibre est détecté au nœud 25. 50 25 70 2 4 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62 40

Les rotations On vérifie l’équilibre nœud par nœud, en remontant le long du chemin parcouru depuis la racine. Un déséquilibre est détecté au nœud 25. Le nœud sous-critique est le nœud 36. 50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62 40

Les rotations On constate que l’arbre sous-critique penche dans le même sens que le déséquilibre au nœud critique. On aura donc une seule rotation à faire. 50 25 70 36 13 60 85 28 8 17 45 55 64 90 26 38 48 62 40

Les rotations On a une seule rotation à faire. 50 70 25 36 60 85 13 28 45 55 64 90 8 17 26 38 48 62 40

Les rotations On a une seule rotation à faire. 50 70 25 36 60 85 13 28 45 55 64 90 8 17 26 38 48 62 40

Les rotations On a une seule rotation à faire. 50 70 25 36 60 85 13 28 45 55 64 90 8 17 26 38 48 62 40

Les rotations On a une seule rotation à faire. 50 70 36 25 60 85 45 13 28 55 64 90 38 48 8 17 26 62 40

Les rotations On a une seule rotation à faire. 50 70 36 25 60 85 45 13 28 55 64 90 38 48 8 17 26 62 40

Les rotations On a une seule rotation à faire. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Les rotations On a une seule rotation à faire. Nous avons donc rééquilibré l’arbre à partir du nœud critique que nous avions. Il reste encore à vérifier l’équilibre pour le reste du chemin en remontant à la racine, car il pourrait y en avoir d’autres. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Les rotations On a une seule rotation à faire. Nous avons donc rééquilibré l’arbre à partir du nœud critique que nous avions. Il reste encore à vérifier l’équilibre pour le reste du chemin en remontant à la racine, car il pourrait y en avoir d’autres. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Les rotations En l’occurrence, il ne reste qu’à vérifier qu’il n’y a pas de déséquilibre au nœud 50. 50 4 4 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Les rotations On a une seule rotation à faire. Nous avons donc rééquilibré l’arbre à partir du nœud critique que nous avions. Il reste encore à vérifier l’équilibre pour le reste du chemin en remontant à la racine, car il pourrait y en avoir d’autres. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Implémentation d’une rotation Nœud *rotation_gauche(Nœud *racine) { Nœud *nouvelle_racine=racine->droite; racine->droite = nouvelle_racine->gauche; nouvelle_racine->gauche = racine; return nouvelle_racine; } 36 25 36 13 25 45 28 13 28 38 48 8 17 45 26 38 48 8 17 26 40 40

Implémentation d’un rééquilibre Nœud *reequilibrer_si_necessaire(Nœud *racine) { int diff; if(!racine) return racine; diff = hauteur(racine->droite)-hauteur(racine->gauche); if(diff>1) Nœud *sous_critique = racine->droite; int diff_sous_critique = hauteur(sous_critique->droite)-hauteur(sous_critique->gauche); if(diff_sous_critique<0) sous_critique = rotation_droite(sous_critique); racine=rotation_gauche(racine); } else if(diff<-1) Nœud *sous_critique = racine->gauche; if(diff_sous_critique>0) sous_critique = rotation_gauche(sous_critique); racine=rotation_droite(racine); return racine;

Intégration du rééquilibre dans l’algorithme d’ajout Nœud *ajout(Nœud *racine, float nouvelle_valeur) { if(!racine) racine = malloc(sizeof(Nœud)); racine->gauche=racine->droite=0; racine->valeur = nouvelle_valeur; } else if(nouvelle_valeur<racine->valeur) racine->gauche = ajout(racine->gauche,nouvelle_valeur); else if(nouvelle_valeur>racine->valeur) racine->droite = ajout(racine->droite,nouvelle_valeur); return reequilibrer_si_necessaire(racine);

Algorithme de recherche du successeur Dans un ensemble ordonné, le successeur d’une valeur est la valeur qui la suit immédiatement dans l’ordre. Par exemple, dans l’ensemble ordonné { 3, 6, 7, 12, 17, 18, 22 }, le successeur de 12 est 17, le successeur de 3 est 7, et 22 n’a pas de successeur.

Algorithme de recherche du successeur Dans un arbre AVL, le successeur peut être découvert en descendant une fois à droite, puis autant de fois que l’on peut à gauche. Par exemple, dans cet arbre-ci, le successeur de 50 est 55. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Algorithme de recherche du successeur Le successeur de 70 est 85. En effet, on descend une fois à droite, et on va à gauche tant et aussi longtemps qu’on le peut, mais ça c’est bien s’il y a un enfant de gauche. Sinon, on a déjà trouvé le successeur. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Algorithme de recherche du successeur Comment faire pour retrouver le successeur d’un nœud qui n’a pas d’enfant de droite? Par exemple, comment faire pour trouver le successeur de 28? 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Algorithme de recherche du successeur Ce qu’il faut faire, dans ce cas, c’est remonter de parent en parent jusqu’à ce que ce soit vers la droite que se trouve le parent. Dès que l’on a remonté une fois vers la droite, alors nous avons le successeur. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Algorithme de recherche du successeur Si, par ce processus, on aboutit à la racine en n’ayant jamais remonté à droite, c’est alors parce que le nœud n’a pas de successeur. 50 36 70 25 60 85 45 13 28 55 64 90 38 48 8 17 26 40 62

Implémentation de l’algorithme de recherche du successeur Nœud *successeur(Nœud *racine, float valeur) { if(!racine) { ??? (nous aborderons ce cas plus tard) } // Il faut d’abord retrouver le nœud dont on cherche le successeur. if(valeur<racine->valeur) return successeur(racine->gauche,valeur); else if(valeur>racine->valeur) return successeur(racine->droite,valeur); else if(valeur==racine->valeur) // On a trouvé le nœud dont on cherche le successeur. if(racine->droite) // Cas simple Nœud *i=racine->droite; //Une fois à droite while(i->gauche) i=i->gauche; // À gauche tant et aussi longtemps qu’on peut. return i; } else // Cas compliqué { // Comment faire quand le nœud dont on cherche le successeur n’a pas d’enfant de droite?

Implémentation de l’algorithme de recherche du successeur Pour résoudre le cas compliqué, l’astuce est la suivante: la fonction récursive retourne tout simplement zéro comme réponse! Cela est pour signifier à l’appelant que cet appel-ci n’a pas été capable de trouver le successeur. Puis, à l’endroit où la fonction fait un appel récursif sur l’enfant de gauche, avant de retourner simplement la réponse reçue, on vérifie si c’est zéro qui a été retourné. Si c’est le cas, alors le successeur est précisément le nœud « racine »!

Implémentation de l’algorithme de recherche du successeur Nœud *successeur(Nœud *racine, float valeur) { if(!racine) { ??? } if(valeur<racine->valeur) Nœud *s = successeur(racine->gauche,valeur); if(s==0) return racine; // Ceci résout le cas compliqué! return s; } else if(valeur>racine->valeur) return successeur(racine->droite,valeur); else if(valeur==racine->valeur) // On a trouvé le nœud dont on cherche le successeur. if(racine->droite) // Cas simple Nœud *i=racine->droite; while(i->gauche) i=i->gauche; return i; else return 0; // Cas compliqué: on retourne zéro!

Implémentation de l’algorithme de recherche du successeur Dans le cas où la valeur dont on cherche le successeur n’est pas présente dans l’arbre, on pourrait avoir comme réflexe de retourner un code d’erreur. Par contre, il faut sauter sur l’occasion pour implémenter un algorithme bien plus puissant, puis de retourner quand même le successeur de cette valeur. Pour ce faire, il suffit de retourner zéro, et la même ligne de code qui réglait le cas compliqué retournera la bonne valeur pour le cas où la valeur est introuvable.

Implémentation de l’algorithme de recherche du successeur Nœud *successeur(Nœud *racine, float valeur) { if(!racine) return 0; // Ceci sera résolu de la même façon que le cas compliqué. if(valeur<racine->valeur) Nœud *s = successeur(racine->gauche,valeur); if(s==0) return racine; // Ceci résout aussi le cas de la valeur absente dans l’arbre! return s; } else if(valeur>racine->valeur) return successeur(racine->droite,valeur); else if(valeur==racine->valeur) if(racine->droite) Nœud *i=racine->droite; //Une fois à droite while(i->gauche) i=i->gauche; return i; else return 0;

Algorithme du prédécesseur Évidemment, pour implémenter l’algorithme de recherche du prédécesseur, il suffit de faire la même chose, mais en inversant gauche et droite.

Algorithme de suppression Pour supprimer un nœud dans un arbre AVL, il y a deux cas simples et un cas compliqué: Premier cas simple: le nœud à supprimer est une feuille. Dans ce cas, il suffit de le supprimer directement. Deuxième cas simple: le nœud à supprimer possède un seul enfant. Dans ce cas, il suffit de le supprimer et de le remplacer par son seul enfant. Cas compliqué: le nœud à supprimer a deux enfants. Dans ce cas, il faut d’abord échanger ce nœud avec son successeur, puis le supprimer à son nouvel endroit, ce qui nous mènera nécessairement à l’un des deux cas simples. Bien entendu, il faut aussi vérifier les déséquilibres en remontant jusqu’à la racine. L’algorithme fonctionne aussi bien si on prend le prédécesseur plutôt que le successeur. Étant donné que la nécessité de retrouver le successeur ne survient que dans le cas où le nœud a deux enfants, alors nous sommes nécessairement toujours en présence du cas simple de recherche du successeur! Ainsi, une simple boucle suffit.

Exemple de suppression AVL Supprimons le nœud 36 de cet arbre-ci. Il faut d’abord le repérer avec une recherche conventionnelle à partir de la racine. 50 36 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 37 40 62 38

Exemple de suppression AVL Puis, nous établissons qu’il s’agit d’un cas compliqué car le nœud à supprimer a deux enfants. 50 36 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 37 40 62 38

Exemple de suppression AVL Il faut donc d’abord retrouver son successeur à l’aide d’une boucle simple (une fois à droite, plein de fois à gauche). 50 36 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 37 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 36 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 37 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 36 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 37 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 70 36 25 60 85 45 13 28 39 55 64 90 48 37 8 17 26 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 70 36 25 60 85 45 13 28 39 37 55 64 90 48 8 17 26 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 70 25 60 85 45 36 37 13 28 39 55 64 90 48 8 17 26 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 70 37 25 60 85 45 36 13 28 39 55 64 90 48 8 17 26 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 36 8 17 26 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 36 8 17 26 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 37 50 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 37 50 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 37 50 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 37 50 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis on l’échange avec. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Remarquez que la règle d’ordonnancement d’arbre binaire de recherche est temporairement enfreinte. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Ensuite, on continue à descendre récursivement pour supprimer 36, comme si rien n’était. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Puis lorsqu’on retombe sur 36, on arrive nécessairement à l’un des deux cas simple. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Dans ce cas-ci, il s’agit du cas avec un seul enfant. 36 sera donc remplacé par 38. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 36 40 62 38

Exemple de suppression AVL Dans ce cas-ci, il s’agit du cas avec un seul enfant. 36 sera donc remplacé par 38. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 40 62 36 38

Exemple de suppression AVL Dans ce cas-ci, il s’agit du cas avec un seul enfant. 36 sera donc remplacé par 38. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 40 62 38 36

Exemple de suppression AVL Dans ce cas-ci, il s’agit du cas avec un seul enfant. 36 sera donc remplacé par 38. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 40 62 38 36

Exemple de suppression AVL Dans ce cas-ci, il s’agit du cas avec un seul enfant. 36 sera donc remplacé par 38. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62 36

Exemple de suppression AVL Dans ce cas-ci, il s’agit du cas avec un seul enfant. 36 sera donc remplacé par 38. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62 36

Exemple de suppression AVL Puis le nœud 36 est détruit avec « free ». Ensuite, il faut remonter jusqu’à la racine pour vérifier l’équilibre de l’arbre. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62

Exemple de suppression AVL Puis le nœud 36 est détruit avec « free ». Ensuite, il faut remonter jusqu’à la racine pour vérifier l’équilibre de l’arbre. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 1 1 8 17 26 38 40 62

Exemple de suppression AVL Puis le nœud 36 est détruit avec « free ». Ensuite, il faut remonter jusqu’à la racine pour vérifier l’équilibre de l’arbre. 50 37 70 25 60 85 45 2 1 13 28 39 55 64 90 48 8 17 26 38 40 62

Exemple de suppression AVL Puis le nœud 36 est détruit avec « free ». Ensuite, il faut remonter jusqu’à la racine pour vérifier l’équilibre de l’arbre. 50 37 70 3 3 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62

Exemple de suppression AVL Puis le nœud 36 est détruit avec « free ». Ensuite, il faut remonter jusqu’à la racine pour vérifier l’équilibre de l’arbre. 50 4 4 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62

Les parcours d’arbre Parcours symétrique (donne les nœuds en ordre croissant): Gauche, racine, droite. Parcours anti-symétrique (donne les nœuds en ordre décroissant): Droite, racine, gauche. Parcours par priorité aux pères (aucune interprétation simple): Racine, gauche, droite (ou racine, droite, gauche). Parcours par priorité aux fils (aucune interprétation simple): Gauche, droite, racine (ou droite, gauche, racine). Parcours rangée par rangée: Ne peut pas s’implémenter par une fonction récursive simple. On doit l’implémenter comme un parcours de graphe par largeur, donc avec une file.

Implémentation de parcours d’arbre void parcours_symétrique(Nœud *racine) { if(!racine) return; parcours_symétrique(racine->gauche); traitement(racine); // Traitement quelconque. parcours_symétrique(racine->droite); } void parcours_anti_symétrique(Nœud *racine) parcours_anti_symétrique(racine->droite); traitement(racine); parcours_anti_symétrique(racine->gauche); void parcours_par_priorite_aux_peres(Nœud *racine) parcours_par_priorite_aux_peres (racine->gauche); // Ça pourrait être droite avant gauche. parcours_par_priorite_aux_peres (racine->droite); void parcours_par_priorite_aux_fils(Nœud *racine) parcours_par_priorite_aux_fils (racine->gauche); // Ça pourrait être droite avant gauche. parcours_par_priorite_aux_fils (racine->droite);

Traces de parcours d’arbre Soit cet arbre-ci: 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62

Traces de parcours d’arbre Parcours symétrique: 8, 13, 17, 25, 26, 28, 37, 38, 39, 40, 45, 48, 50, 55, 60, 62, 64, 70, 85, 90. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62

Traces de parcours d’arbre Parcours anti-symétrique: 90, 85, 70, 64, 62, 60, 55, 50, 48, 45, 40, 39, 38, 37, 28, 26, 25, 17, 13, 8. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62

Traces de parcours d’arbre Parcours par priorité aux pères (gauche avant droite): 50, 37, 25, 13, 8, 17, 28, 26, 45, 39, 38, 40, 48, 70, 60, 55, 64, 62, 85, 90. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62

Traces de parcours d’arbre Parcours par priorité aux fils (gauche avant droite): 8, 17, 13, 26, 28, 25, 38, 40, 39, 48, 45, 37, 55, 62, 64, 60, 90, 85, 70, 50. 50 37 70 25 60 85 45 13 28 39 55 64 90 48 8 17 26 38 40 62