Les arbres Structures les plus importantes et les plus utilisées en informatique Liste = cas dégénéré d arbre Eemples: Arbres généalogiques Arbres de classification Arbres d epression / - Traduction de l epression ( ( )) / ( ) fils gauche Les arbres binaires racine fils droit Soit un arbre A = <o, A 1 > racine de A, le nœud o sous-arbre gauche de A (ou o), l arbre A 1 sous-arbre droit de A (ou o), l arbre A sous-arbre de A, un arbre C quelconque tq soit C = A soit C est sous-arbre de A 1 soit C est sous-arbre de A TAD arbre binaire tpe arbre paramètre nœud opérations : arbre <_, _, > : nœud arbre arbre arbre racine : arbre nœud g : arbre arbre d : arbre arbre préconditions racine(a) : a g(a) : a d(a) : a aiomes o : nœud, A 1 : arbre racine(<o, A 1 >) = o g(<o, A 1 >) = A 1 d(<o, A 1 >) = A Terminologie avancée (1) fils gauche de n = racine de son sous-arbre gauche fils droit de n = racine de son sous-arbre droit fils de n = l un quelconque des nœuds fils gauche et fils droit père de n = le nœud, s il eiste dont n est un fils ascendant de n = tout nœud qui est, soit père de n, soit ascendant du père de n descendant de n = tout nœud dont n est ascendant = fils de n ou descendant d un fils de n = nœud quelconque du sous-arbre droit ou du sousarbre gauche Terminologie avancée () Terminologie avancée () nœud interne = nœud qui a deu fils nœud interne au sens large = nœud qui a un fils arbre complet = un arbre qui n a pas de nœud interne au sens large feuille = un nœud qui n a pas de fils branche de l arbre = tout chemin de la racine à l une de ses feuilles bord gauche de l arbre = le plus long chemin depuis la racine en ne suivant que les fils gauches bord droit de l arbre = le plus long chemin depuis la racine en ne suivant que les fils droits chemin de à n, descendant de, la suite de nœuds {n 0, n 1,..., n p } telle que n 0 =, n p =n et i [1..p], n i-1 = père(n i ) unique on note p sa longueur occurrence de n, le mot de {0, 1} représentant le chemin de la racine à n tq : occurrence(r) = mot vide occurrence(fils gauche de ) = occurrence() 0 occurrence(fils droit de ) = occurrence() 1 1
Mesures sur les arbres (1) Mesures sur les arbres () taille de l arbre = le nombre de ses nœuds, noté taille(a) nombre de feuilles, noté nf(a) hauteur d un nœud = la longueur du chemin qui relie la racine à ce nœud = longueur de l occurrence du nœud, noté h() hauteur de l arbre = la longueur de la plus longue branche, noté h(a) h(a) = ma {h() nœud de A} longueur de cheminement de l arbre = somme des longueurs de tous les chemins issus de la racine LC(A) = {h() nœud de A} longueur de cheminement eterne de l arbre = somme des longueurs de toutes les branches issues de la racine LCE(A) = {h() feuille de A} profondeur moenne (d un nœud) de l arbre = moenne des hauteurs de tous les nœuds PC(A) = LC(A) / taille(a) profondeur moenne eterne (d une feuille) de l arbre = moenne des longueurs de toutes les branches PCE(A) = LCE(A) / nf(a) Propriétés sur les arbres (1) Propriétés sur les arbres () Lemme1. taille(a) nf(a) 1 égalité pour un arbre complet Lemme. h(a) taille(a) 1 égalité pour un arbre dégénéré Lemme. taille(a) h(a)1-1 égalité pour un arbre complet dont toutes les feuilles ont la profondeur h(a) Corollaire 4. log taille(a) h(a) taille(a) 1 log nf(a) h(a) minorant atteint pour les arbres complets dont toutes les feuilles ont la profondeur h(a) majorant pour les arbres dégénérés Lemme 5. A, LCE(A) nf(a) log nf(a) égalité pour arbres complets dont toutes les feuilles ont la profondeur h(a) Corollaire 6. A, PCE(A) log nf(a) Lemme 7. A, LC(A) (taille(a) 1).log (taille(a) 1) taille(a) Corollaire 8. A, PC(A) (taille(a) 1) / taille(a) log (taille(a) 1) - Corollaire 9. A, PC(A) log nf(a) 1 Lemme 10. soit A, un arbre complet non vide de taille n PC(A) = (n 1)/n PCE(A) (n-1)/n Eploration Parcours en largeur d abord (1) pas aussi simple que dans le cas des listes pas d ordre «naturel» Deu tpes de parcours En largeur d abord En profondeur d abord trois tpes principau de préfié infié postfié Ordre d évaluation des noeuds : / - / -
Parcours en largeur d abord () Parcours en profondeur d abord ParcourirEnLargeur(a : Noeud) ce_niveau = {a} tantque ce_niveau est non vide { niveau_inférieur = {} pour chaque nœud o de ce_niveau faire traiter o niveau_inférieur = niveau_inférieur les enfants de o fait ce_niveau = niveau_inf érieur tq Ordre d évaluation des noeuds : Ça dépend... / - Parcours en profondeur : algo Parcours en profondeur : e. procédure eplorer (A : arbre) si A = alors trait_arbre_vide sinon trait_préfié(racine(a)) eplorer(g(a)) trait_infié(racine(a)) eplorer(d(a)) trait_postfié(racine(a)) si préfié infié postfié Parcours infié / Parcours préfié : / Parcours postfié - / / - Implantation contiguë par linéarisation - 1 Implantation contiguë par linéarisation - Possible de linéariser un arbre sans perte d information (parcours préfié ou postfié) Représentation contiguë de la liste préfiée E: / - / - Parcours en profondeur préfié : en O(n) Accès au fils : étant donné un nœud de rang k le rang de son fils gauche est k1 Le rang de son fils droit est? procédure un peu compliquée algos de recherche en O(n) ajout ou suppression dans l arbre insertion ou suppression dans la liste préfiée déplacements en O(n)
Implantation contiguë par niveau 1 Implantation contiguë par niveau a tout nœud, on associe un numéro égal au code de son occurrence, noté code() Occurrence de : pour tout nœud, mot de {0, 1} Code bijection entre {0, 1} et N code : {0, 1} N code(ε) = 1 code(µ0) = code(µ) code(µ1) = code(µ) 1 Pour tout nœud : code(père()) = code() div code(filsgauche()) = code() code(filsdroit()) = code() 1 h() = log code() corollaires pour tout nœud de niveau p code() [ p.. p1 [ pour tout nœud d un arbre A code() < h(a)1 Implantation contiguë par niveau Implantation contiguë par niveau 4 Représentation : espace mémoire contigu au moins h(a)1 1 emplacements numérotés à partir de 1 on range à l indice code() si l emplacement ne correspond pas à un nœud, il est marqué ineistant E: / - / - algos efficaces pour la recherche et l eploration ajout d un nœud changer la marque d ineistence suppression d un nœud marquage de l emplacement correspondant suppression des sous-arbres gauche et droit déplacement d un sous arbre déplacement de l ensemble des nœuds du sous-arbre Implantation contiguë par niveau 5 Implantation chaînée (1) Problème majeur : mauvaise occupation mémoire occupation à 100% dans le cas des arbres binaires parfaits Déition arbre binaire où toutes les feuilles sont sur deu niveau, l avant-dernier étant complet et où toutes les feuilles du dernier niveau sont regroupées à gauche Lemme Un arbre binaire A est parfait ssi nœud de A, code() taille(a) h(a) = log taille(a) La plus naturelle class Nœud { Object contenu ; Nœud gauche = null ; Nœud droit = null ; } noeud null null null null 4
Implantation chaînée () algos efficaces pour la recherche et l eploration Ajout/suppression de nœuds modification d une référence déplacement d un sous arbre Modification de références Arbres générau et forêts Arbre général arbre où les nœuds peuvent avoir nombre quelconque de fils Forêt collection d arbres en nombre quelconque E: recherche des coups à jouer au échecs arbre à lettres a e s o n l m m e t t t d r o m e Arbres générau - terminologie on parle plutôt de : premier fils, deuième fils, etc. fils aîné et frère droit bijection avec les arbres binaires en posant fils_gauche() = aîné () fils_droit() = frère_droit() Arbres générau - parcours procédure eplor_gen(a : arbregen) var i : entier ; f : forêt ; n : nœud f := sousarbres(a) n := racine(a) si f = alors trait_feuille(n) sinon trait_(n) pour i := 1 jusqu à longueur(f) faire (n, i) eplore_gen(ième (f, i)) fait trait_(n) si Arbres générau - implantation Représentation contiguë par linéarisation nécessaire de connaître le nb de fils pour chaque nœud avantages et inconvénients idem arbre binaire Représentation contiguë par niveau nécessaire de borner le nb de fils aggravation de la mauvaise occupation mémoire Représentation chaînée avec un pointeur par fils nécessaire de borner le nb de fils adapté pour arbres p-aires perte de place (p pointeurs fils même pour une feuille) Représentation chaînée avec aîné et frère droit deu pointeurs par nœud quelque soit le nb de fils variante : booléen frère_null indique si frère droit ou pas (frère droit remplacé par père si ineistant) 5