Série d exercices N 9 Arbres Exercice 1 a) Ecrire une fonction ARBIN creerarbreentiers() qui permet de créer et de renvoyer l arbre d entiers suivant : b) Ecrire une fonction int feuilles(arbin a) qui permet de c) compter le nombre de feuilles d un arbre. d) Ecrire une fonction void inverserarbre(arbin a) qui permet d inverser un arbre d entiers (fils gauche devient fils droit et vice versa). Exercice 2 (Session Principale 2003/2004) Procédure FileArbre (A : ArbreBinaire) F : File de noeuds d un arbre binaire P : Noeud d un arbre binaire Début Initialiser(F) // Création d une file vide Enfiler(F, A->refRacine) Tantque NonVide(F) Faire P <- Défiler(F) Afficher(P->Info) Si P->FG ¹ NULL Alors Enfiler(F, P->FG) Finsi Si P->FD ¹ NULL Alors Enfiler(F, P->FD) Finsi Fin Tantque Fin En utilisant la procédure FileArbre, donner l'ordre d'affichage des noeuds de l'arbre ci-contre Exercice 3 (Session Principale 2004/2005) exercice pour TP Dans cet exercice, on se propose de traiter des arbres binaires partiellement équilibrés en utilisant le type arbre binaire ARBIN. Un arbre binaire est dit partiellement équilibré s il est vide ou si pour chaque noeud de l arbre les hauteurs de ses sous arbres gauches et droits diffèrent de au plus 1. a) En utilisant les primitives d un arbre binaire (ARBIN), écrire une fonctions récursive int equilibre(arbin a) qui retourne 1 (vrai) si l arbre a satisfait la définition d un arbre binaire partiellement équilibré et 0 (faux) sinon. Soit un arbre binaire a manipulant des éléments nommés CarHauteur. Un élément CarHauteur est déclaré dans le fichier ELTCARHAUT.H comme suit : typedef struct { char car ; int hauteur ; CarHauteur, * ELEMENT ; 1
b) Ecrire une fonctions récursive void calculerhauteurs(arbin a) qui prend en argument un arbre binaire de ce type. Cette fonction modifie l arbre en entrée en mettant à jour le champ hauteur de chaque noeud de façon à ce qu il contienne la hauteur du sous arbre dont il est la racine. c) En employant la fonction calculerhauteurs, donner une nouvelle implémentation de fonction equilbre (question a). Exercice 4 (Session Principale 2004/2005) Soit le type arbre épine dorsale qui est un arbre ternaire structuré de la manière suivante : a) Remplir les blancs relatifs à la figure ci-dessus : La profondeur de cet arbre est.. L ordre de cet arbre est.. Le résultat du parcours postfixé est.. La liste A,B,Z,X,C,E,Y,D,R,M,F,N est un le résultat du parcours.. Les noeuds B, Z, X appartiennent au niveau.. A-Z-E-R est.. L implémentation chaînée de la structure de données épine dorsale va se faire dans les fichiers ARBED.H et ARBED.C. b) Ecrire le code de fichier ARBED.H qui permet de déclarer le type arbre épine dorsale. c) Ecrire une fonction itérative int tailleed(arbed a) qui permet de renvoyer la taille d un arbre épine dorsale. d) Ecrire une fonction itérative int verifiered(arbed a) qui permet de renvoyer 1 (vrai) si l arbre a est épine dorsale et 0 si non (faux). Exercice 5 (Session principale 2005/2006) On définit un tas comme étant un arbre binaire parfait tel que l information contenue dans chaque noeud est inférieure à celles contenues dans ses deux fils. Le minimum de l ensemble représenté par un tas est donc à la racine (C est le cas de l exemple ci-dessous). Les traitements sur les tas nécessitent que chaque noeud puisse accéder à son père ainsi qu à ses fils. On se propose d implémenter les primitives de structure de données TAS suivants : - int tasinserer(tas t, ELEMENT e) ; - ELEMENT supprimermin(tas t) ; - ELEMENT tasracine(tas t) ; - int tasvide(tas t) ; - int tassature(tas t) ; - etc 2
a) Ecrire le code de fichier TASPTR.H qui permet d implémenter le tas d une façon chaînée. e) Un arbre binaire parfait de taille n peut se représenter de façon très compacte dans un tableau T de taille au moins égale à n + 1 (la première cellule de T, de rang 0, n est pas utilisée). La représentation est la suivante: La racine est en T[1] et si un noeud est en T[i], son fils gauche est en T[2i] et son fils droit en T[2i+1]. b) Donner la représentation dans le cas de l arbre ci-dessus. c) Quel est l instruction qui permet de récupérer le père d un noeud i. d) Pourquoi cette représentation contiguë est-elle adéquate avec les Tas. e) Ecrire le code de fichier TASTAB.H qui permet d implémenter le tas d une façon contiguë. Insertion d un élément à un tas Le problème est d ajouter un élément e à un tas tout en conservant une structure de tas. On commence par rajouter l élément e comme feuille au dernier niveau de l arbre puis on échange l information du nœud portant e avec celui de son père jusqu à ce que, pour respecter la structure de tas, e ne soit pas inférieur à l information du père du noeud qui le porte. Par exemple, pour rajouter 4 au tas donné dans l exemple ci-dessus, on obtient les étapes suivantes : f) Ecrire une fonction itérative int tasinserer(tas t, ELEMENT e) qui permet d insérer un élément e à un tas t. En supposant que la fonction NOEUDTAS dernierpere(tas t) qui retourne le père de e est donnée. Dans l exemple précédant la fonction dernierpere() retourne le noeud contenant 8. La complexité temporelle de cette fonction est de O(N), N étant la taille de l arbre. g) Donner la complexité temporelle de cet algorithme avec une brève explication. Suppression du minimum d un tas (la racine) h) Ecrire une fonction itérative ELEMENT supprimermin(tas t) qui permet de supprimer le minimum du tas courant et retournant la valeur de ce minimum, en utilisant la représentation contiguë. L idée est de supprimer la dernière feuille du dernier niveau après avoir recopié son information à la racine, puis, pour respecter la structure de tas, de faire redescendre cette valeur en la comparant au contenu de ses fils, par un processus inverse de celui de l insertion. La figure suivante illustre ce processus dans le cas de l exemple. 3
Exercice 6 (Session Principale 2007/2008) Un arbre lexicographique est un arbre binaire qui représente un dictionnaire tel que: - Chaque noeud contient un caractère - Le fils droit signifie le caractère suivant dans le mot. - Le fils gauche signifie le caractère suivant dans le dictionnaire (alternative). Le caractère * signifie la fin d un mot. Il est à noter qu'un noeud "fin de mot" n'a pas de sousarbre droit mais peut avoir un sous arbre gauche. Par exemple, l'arbre suivant correspond aux 8 mots : a bac balle ballon bas base bus sac La structure arbre lexicographique peut être implémentée par un arbre binaire dont les éléments sont de caractères (ELTCAR.H et ELTCAR.C). a) Donner la trace d exécution de la fonction f suivante : public void f (ARBIN a) { char mot[20] ; g (a->refracine, mot,0); void g (NOEUD n, char m[], int i) { if (n!= NULL) { if (n->info == * ) { 4
m[i] = \0 ; printf( %s, m); else { m[i] = n->info; g (n->fd, m, i + 1); g (n->fg, m, i); Quelle est l utilité de cette fonction? b) Ecrire une fonction récursive int existerec(arbin a, char mot[]) qui permet de tester l existence d un mot dans un arbre lexicographique. c) Ecrire une fonction itérative int existeit(arbin a, char mot[]) qui permet de tester l existence d un mot dans un arbre lexicographique. 5