IFT2810 Automne 2008

Introduction aux arbres

1

Concepts de base

Un arbre est constitu´ d’un ensemble de nœuds et de branchesreliant les nœuds. e Le degr´ d’un nœud est le nombre de branches connect´es au nœud. Le premier nœud e e ` part la racine, tous les nœuds de d’un arbre (celui sans branche entrante) est la racine. A l’arbre ont une seule branche entrante. Chaque nœud de l’arbre peut avoir, 0, 1 ou plusieurs branches sortantes. Un nœud avec 0 branches sortantes est une feuille. Les nœuds autre que la racine et les feuilles sont appel´s nœuds internes. Si une branche sortante relie u e ` v, alors u est le p`re de v et v est le fils de u. Deux nœuds adjacents sont deux nœuds a e reli´s par une branche. Un chemin est une suite de nœuds adjacents. Tout nœud peut ˆtre e e atteint en suivant un chemin unique de la racine ` ce nœud. Le niveau d’un nœud v est a le nombre de nœuds sur le chemin de la racine au p`re de v. En particulier, la racine est e au niveau 0, et les fils de la racine sont au niveau 1. Un ancˆtre d’un nœud v est tout e nœud sur le chemin de v ` la racine. En particulier, la racine est l’ancˆtre de tous les autres a e nœuds. Le descendant d’un nœud v est tout nœud sur le chemin de v ` une feuille de a l’arbre. En particulier, tous les nœuds sont des descendants de la racine. La hauteur (ou profondeur) d’un arbre est le plus haut niveau de l’arbre plus 1. Par exemple, le niveau de l’arbre ` la figure 1 est 4. a Un sous-arbre est toute structure connect´e en dessous de la racine. Par exemple, e dans la figure 1, le sous-arbre de racine B contient les nœuds B, C, D, J.

2

Arbre binaire

Un arbre est binaire si chaque nœud de l’arbre a au plus deux fils (0, 1 ou 2 fils) (figure 2). Les deux fils d’un nœud sont appel´s fils gauche et fils droit. Un nœud peut e avoir 0 fils, un fils gauche uniquement, ou un fils droit uniquement. – La hauteur maximale d’un arbre binaire de N nœuds est Hmax = N. – La hauteur minimale d’un arbre binaire de N nœuds est Hmin = ⌊log2 (N)⌋ + 1. – Un arbre binaire de hauteur H a un minimum de Nmin = N nœuds et un maximum de Nmax = 2H − 1 nœuds. Moins un arbre est haut, plus la recherche d’un nœud dans cet arbre est efficace.

1

e e A B F C D G E Fig.niveau 0 A racine niveau 1 B pere E F niveau 2 C D fils G H I feuille niveau 3 J Fig. 1 – Arbre g´n´ral. 2 – Arbre binaire balanc´ e 2 .

3 – Arbre complet Arbre complet Un arbre binaire de hauteur H est complet s’il a le maximum de nœuds pour sa hauteur. de hauteur Hmin = ⌊log2 (N)⌋ + 1. ou les deux. e e A B E C D F G Fig. autrement dit. Un arbre binaire de N nœuds est presque complet s’il est de hauteur minimale. i. 4 – Arbres balanc´s. e – A est balanc´ ssi Al et Ar ont une hauteur qui diff`re d’au plus 1 (0 ou 1 ou -1) et e e les sous-arbres de Al et Ar sont aussi balanc´s. a A A B E B E C C D F Fig. peuvent ˆtre vides). 2H − 1 nœuds (figure 3). e L’arbre de la figure 2 est balanc´. L’arbre de la figure 3 est aussi balanc´.e. e 3 .Arbre balanc´ Soit A un arbre de racine r. Ar les deux sous-arbres de A de racines e respectives les fils gauche et droit de r (l’un des deux sous-arbres. et Al . et deux pointeurs : un vers le fils gauche et un vers le fils droit. et si tous les nœuds du dernier niveau se retrouvent ` gauche de l’arbre (Figures 4). presque complets e Structure d’un arbre binaire Chaque nœud de la structure doit contenir un champs pour les donn´es. e – Un arbre vide est balanc´.

explorer le nœud. Il existe trois sortes de parcours en profondeur. puis son fils droit.noeud data filsGauche filsDroit fin noeud <type de donnees> <pointeur vers noeud> <pointeur vers noeud> 3 Parcours d’un arbre binaire Un parcours d’arbre doit passer par chaque nœud une et une seule fois.1 Parcours en profondeur Soit A un arbre de racine r. Ce sont des proc´dures r´cursives e e d´crites de la fa¸on suivante : e c 1. explorer son fils gauche. 5 – Sous-arbres gauche et droit d’un arbre binaire. racine sous-arbre gauche sous-arbre droit Fig. Parcours en postordre : Pour chaque nœud. e 4 . puis le nœud lui mˆme. Parcours en pr´ordre : Pour chaque nœud de l’arbre. 3. Il existe deux parcours : parcours en profondeur (depth-first traversal) et parcours en largeur (breadth first traversal). puis le nœud lui mˆme. puis son fils droit. puis son fils droit. explorer son fils gauche. 2. Parcours en ordre : Pour chaque nœud de l’arbre. de sous-arbre gauche Al et de sous-arbre droit Ar . e 3. puis son fils e gauche.

2 Parcours en largeur Dans un parcours en largeur. 5. Si (racine = NULL) 2. Pour cela. postOrdre(racine->filsGauche). 4. preOrdre(racine->filsGauche). 3. Si (racine = NULL) 2. 5. traiter(racine) . traiter(racine) . 4. 4.Parcours en pr´ordre e Algorithme preOrdre (racine <pointeur-arbre>) 1. on explore tous les nœuds d’un niveau n avant de passer au niveau n + 1. traiter(racine) . 3. enOrdre(racine->filsGauche) . enOrdre(racine->filsDroit) . 5. 5 . Fin Si Parcours en ordre Algorithme enOrdre (racine <pointeur-arbre>) 1. postOrdre(racine->filsDroit). Fin Si Parcours en postordre Algorithme postOrdre (racine <pointeur-arbre>) 1. on utilise une file. Fin Si 3. Si (racine = NULL) 2. 3. preOrdre(racine->filsDroit).

insereFile(file.pointeur) . 13. Si (pointeur->filsGauche = NULL) 6. creeFile(file) . Si (fileVide(file) = Faux) 12.D / B C C E −→ −→ −→ −→ A A A A B B B B * * C + C * + C * + D E / - 6 . e e e e c e e postfix´e et pr´fix´e. Fin Si 16. e e e e e Transformation d’une expression infix´e en une expression postfix´e : e e A * A * B + A + B * A + B * C . e e e Exp. pointeur := racine . Fin Si 8. 3. traiter(pointeur) .pointeur->filsGauche) . Les expressions infix´es doivent ˆtre transform´es en expressions postfix´es ou e e e e e e pr´fix´es pour pouvoir ˆtre ´valu´es par les langages de programmation. 10. Infix´e : e a + b Exp. insereFile(file. Pr´fix´e : + a b e e Exp. pointeur->filsDroit) . 15. Si (pointeur->filsDroit = NULL) 9. 5. Fin Tant que 4 Application : arbres d’expressions Une expression arithm´tique peut-ˆtre repr´sent´e de trois fa¸ons diff´rentes : infix´e. Sinon 14. pointeur := NULL . Postfix´e : a b + e Les expressions postfix´es et pr´fix´es ne n´cessitent pas de parenth`ses pour ˆtre e e e e e e ´valu´es. supprimeFile(file. 7.Algorithme parcoursLargeur (racine <pointeur-arbre>) 1. Tant que (pointeur = NULL) 4. 2. Fin Si 11.

6. Sinon Si (donnee = ) ) 9. donnee := expression[indice] . 18.donnee) . Fin Tant que 14. 4. sommetPile (pile. 24. depile(pile. Tant que ( pileVide(pile) = FAUX) Et (priorite(donnee) <= priorite(top)) ) 17. on l’imprime. 3. concatene(postFix. on d´pile tous les op´rateurs qui e a e e e e ont une pr´c´dence sup´rieure ` celle de o.donneeOut) . 8. indice := 0 . concatene(postFix. e e e a Algorithme inToPostFix (expression. Sinon 23.donnee) . Fin Si 25. creePile (pile) . empile (pile.donnee) . postFix) 1. 7 .donneeOut) . 30. 13. Tant que (pileVide(pile) = FAUX) 28. 10. Supposons que le caract`re lu a e e e soit l’op´rateur o. 26. 2. empile (pile.donnee) . depile (pile. 19. depile (pile. Tant que ( donnee = ( ) 11. Fin Tant que 31. Retourne (postFix) . concatene(postFix. concatene(postFix. Sinon Si (donnee est un operateur) 15. top) . Si la pr´c´dence de o est e e e e sup´rieure ` la pr´c´dence de p. Si le caract`re lu est un op´rande. alors on empile o. Fin Tant que 27. sommetPile (pile. depile (pile. Au e e d´but la pile est vide. 20.Avec une pile : On utilise une pile pour empiler les op´rateurs successifs rencontr´s.donnee) . Si ( donnee = ( ) 7. indice := indice + 1 . 29. 22. top) . et que l’op´rateur du sommet de pile soit p.donnee) .donnee) . postFix := motVide . Tant que (indice < taille-expression) 5. L’id´e de l’algorithme est la suivante : Lire l’expression de gauche e e ` droite. Sinon. 12. 16. Fin Tant que 21.donnee) .

Fin Si 11. on d´pile les deux derniers ´l´ments de la pile. print(arbre->donnee) .´ Evaluation d’une expression postfix´e On utilise une pile pour empiler les op´randes. e ee Algorithme infix (arbre <pointeur-arbre>) 1. e e Repr´sentation d’une expression par un arbre On utilise un arbre binaire ayant e les propri´t´ suivantes : ee 1. e 3. 9. Sinon 5. Les sous-arbres repr´sentent des sous-expressions. Chaque feuille est un op´rande. Fin Si 8 . Impression de l’expression infix´e On veut d´velopper un algorithme qui parcourt e e l’arbre et imprime l’expression infix´e parenth´s´e. 4. e + * d a + b c Fig. print(‘(’) . 6. et on remet le r´sultat dans la pile. 10. print(arbre->donnee) . infix (arbre->filsGauche) . 8. 7. infix (arbre->filsDroit) . e e Lorsque le caract`re lu est un op´rateur. Si (arbre = NULL) 2. 6 – Arbre de l’expression a ∗ (b + c) + d. on e e e ee effectue l’op´ration correspondante. La racine et les nœuds internes sont des op´rateurs. print(‘)’) . Si (arbre->donnee est un operande) 3. e 2.

postfix (arbre->filsDroit) . 3. 4. e e Algorithme prefix (arbre <pointeur-arbre>) 1. Si (arbre = NULL) 2. Si (arbre = NULL) 2. Fin Si 9 . Fin Si Impression de l’expression pr´fix´e On veut d´velopper un algorithme qui parcourt e e e l’arbre et imprime l’expression pr´fix´e. postfix (arbre->filsGauche) . prefix (arbre->filsGauche) . e Algorithme postfix (arbre <pointeur-arbre>) 1. print(arbre->donnee) . 3. 4. 5. prefix (arbre->filsDroit) .Impression de l’expression postfix´e On veut d´velopper un algorithme qui parcourt e e l’arbre et imprime l’expression postfix´e. print(arbre->donnee) . 5.