Vous êtes sur la page 1sur 4

TP7 : Arbres binaires de recherche

Programmation en C (LC4) Semaine du 1er mai 2006


Dans ce TP, nous allons implmenter des arbres binaires de recherche (ou ABR) et des fonctions pour les manipuler. Un ABR est tout dabord binaire ce qui implique que chacun de ses noeuds peut comporter au maximum deux ls. Il est aussi construit de faon ce quil soit facile de faire une recherche sur les valeurs quil contient. Pour cela, on dnit les deux rgles suivantes : toutes les valeurs infrieures ou gales celle de la racine sont stockes dans le sous-arbre gauche. toutes les valeurs strictement suprieures celle de la racine sont stockes dans le sousarbre droit. Les sous-arbres gauche et droit de la racine sont aussi des ABR. La gure 1 donne un exemple dABR contenant des entiers. Remarque : durant tout le TP, le dtail des structures implmenter ou les protoypes exacts des fonctions ne seront pas donns dans lnonc. Vous tes donc libres dutiliser limplmentation que vous prfrez.

Fig. 1 Un arbre de recherche Exercice 1 Dnissez une structure struct ABR permettant de coder un noeud dABR contenant un entier (en utilisant notamment des pointeurs). Correction typedef struct ABR{ int v a l e u r ; struct ABR gauche ; struct ABR d r o i t e ; }ABR; Exercice 2 crivez une fonction cree_arbre qui prend en argument un entier et renvoie un ABR dun seul noeud contenant cette valeur. 1

Correction ABR c r e e _ a r b r e ( int n ) { ABR a r b r e = (ABR ) m a l l o c ( s i z e o f (ABR) ) ; a r b r e >v a l e u r = n ; a r b r e >gauche = NULL; a r b r e >d r o i t e = NULL; return a r b r e ; } Exercice 3 crivez une fonction affiche_croissant permettant dacher les valeurs des noeuds dun ABR de manire croissante. Correction void a f f i c h e _ c r o i s s a n t _ r e c (ABR a r b r e ) { i f ( a r b r e >gauche ! = NULL) a f f i c h e _ c r o i s s a n t _ r e c ( a r b r e >gauche ) ; p r i n t f ( ",%d , " , a r b r e >v a l e u r ) ; i f ( a r b r e >d r o i t e ! = NULL) a f f i c h e _ c r o i s s a n t _ r e c ( a r b r e >d r o i t e ) ; } void a f f i c h e _ c r o i s s a n t (ABR a r b r e ) { affiche_croissant_rec ( arbre ) ; p r i n t f ( "\n" ) ; } Exercice 4 crivez une fonction affiche_arbre permettant dacher les valeurs des noeuds dun ABR de manire voir la structure de larbre. Un noeud sera ach par (g,v,d) o g est le sous-arbre gauche, v la valeur du noeud et d le sous-arbre droit. Par exemple, larbre prsent dans la gure 1 sera ach par : (((_,1,_),3,_),4,((_,6,_),6,((_,7,_),9,_))). Les _ indiquent les sous-arbres vides. Correction void a f f i c h e _ a r b r e _ r e c (ABR a r b r e ) { printf ("(" ); i f ( a r b r e >gauche ! = NULL) { a f f i c h e _ a r b r e _ r e c ( a r b r e >gauche ) ; } else { p r i n t f ( "_" ) ; } p r i n t f ( ",%d , " , a r b r e >v a l e u r ) ; i f ( a r b r e >d r o i t e ! = NULL) { a f f i c h e _ a r b r e _ r e c ( a r b r e >d r o i t e ) ; } else { p r i n t f ( "_" ) ; } printf (")" ); } void a f f i c h e _ a r b r e (ABR a r b r e ) { affiche_arbre_rec ( arbre ) ; p r i n t f ( "\n" ) ; }

Exercice 5 crivez une fonction ajoute_entier permettant dajouter un entier dans lABR (ce sera une nouvelle feuille bien place dans larbre). Si vous tes coincs : il y a dirents cas considrer : Larbre est vide (pointeur NULL), dans ce cas la fonction de lexercice 2 peut servir. Lentier insrer est plus petit ou gal la valeur de la racine. Et dans ce cas, la racine a-telle dj un ls gauche ? Lentier insrer est plus grand que la valeur de la racine. Et dans ce cas, la racine a-telle dj un ls droit ? Si vous tes toujours coincs : il faut penser faire un appel rcursif de la fonction quand on veut ajouter le noeud dans un sous-arbre qui nest pas vide. Bien vrier que larbre est dun seul bloc et quil ny a pas de pointeurs errants... Correction ABR a j o u t e _ r e c _ e n t i e r (ABR nouveau , ABR a r b r e , ABR noeud ) { i f ( a r b r e == NULL) { return nouveau ; } i f ( nouveau>v a l e u r <= noeud>v a l e u r ) { i f ( noeud>gauche == NULL) { noeud>gauche = nouveau ; } else { a j o u t e _ r e c _ e n t i e r ( nouveau , a r b r e , noeud>gauche ) ; } } else { i f ( noeud>d r o i t e == NULL) { noeud>d r o i t e = nouveau ; } else { a j o u t e _ r e c _ e n t i e r ( nouveau , a r b r e , noeud>d r o i t e ) ; } } return a r b r e ; } ABR a j o u t e _ e n t i e r ( int n , ABR a r b r e ) { ABR nouveau = c r e e _ a r b r e ( n ) ; p r i n t f ( "%d : %p\n" , n , nouveau ) ; return a j o u t e _ r e c _ e n t i e r ( nouveau , a r b r e , a r b r e ) ; } Exercice 6 crivez la fonction trouve_noeud qui prend en argument un entier et un arbre et qui renvoie ladresse dun noeud de larbre contenant cet entier (ou NULL si cet entier nest pas dans larbre). Correction ABR trouve_noeud ( int n , ABR a r b r e ) { i f ( a r b r e >v a l e u r == n ) return a r b r e ; i f ( n <= a r b r e >v a l e u r ) { i f ( a r b r e >gauche ! = NULL) return trouve_noeud ( n , a r b r e >gauche ) ; else return NULL; } else { i f ( a r b r e >d r o i t e ! = NULL)

return trouve_noeud ( n , a r b r e >d r o i t e ) ; else return NULL; } } Exercice 7 crivez une fonction supprime_feuille permettant de supprimer une feuille de larbre contenant un certain entier (pass en argument). Exercice 8 crivez une fonction supprime_noeud1 permettant de supprimer un entier de larbre uniquement sil est contenu par une feuille ou par un noeud nayant quun seul ls. Exercice 9 crivez une fonction supprime_noeud qui permet de supprimer un entier de larbre. Lalgorithme global est le suivant : Si le noeud enlever est une feuile, on lenlve. Si cest un sommet qui na quun ls, on le remplace par ce ls. Si cest un sommet qui a deux ls, le remplacer par le sommet de plus grande valeur dans le sous-arbre gauche, puis supprimer ce sommet en appelant rcursivement la fonction. Il faut bien entendu sinspirer des deux exercices prcdents. Correction void supprime_noeud (ABR pere , int x ) { while ( p e r e ) { i f ( ( p e r e)> v a l e u r==x ) { ABR noeudx=p e r e ; i f ( noeudx>gauche==NULL) p e r e = noeudx>d r o i t e ; e l s e i f ( noeudx>d r o i t e==NULL) p e r e = noeudx>gauche ; else { ABR noeud_droit ; ABR pere_noeud_droit=&noeudx>d r o i t e ; while ( ( pere_noeud_droit)>gauche ) pere_noeud_droit=&(pere_noeud_droit)>gauche ; noeud_droit=pere_noeud_droit ; pere_noeud_droit=noeud_droit>d r o i t e ; noeud_droit>gauche=noeudx>gauche ; noeud_droit>d r o i t e=noeudx>d r o i t e ; p e r e=noeud_droit ; }; f r e e ( noeudx ) ; return ; } e l s e i f ( ( p e r e)>v a l e u r <x ) p e r e =&(( p e r e)>gauche ) ; e l s e p e r e =&(( p e r e)> d r o i t e ) ; } }