Programmation objet Cours n 8 Structures de données partie 3 Arbres binaires de calcul 1
Arbre binaire de calcul Nous avons vu l'utilisation des arbres binaires en tant que structure de données optimisée pour la recherche par valeur sur un critère "binaire". La même structure peut également être utilisée dans un autre cas : Un calcul d'expression mathématiques On parle dans ce cas d'arbre binaire de calcul. La structure est identique, mais son fonctionnement est différent. 2
Principe Lorsqu'on effectue un calcul, on effectue en fait une suite d'opérations Chaque opération utilise deux opérandes Chaque opération fournit un résultat qui peut être utilisé pour une autre opération. On remarque donc que l'ensemble de l'expression de calcul peut se modéliser dans un arbre binaire où les feuilles seront les opérandes et les racines les opérations... 3
Exemple Soit le calcul : 6 3 + 4 2-2 Le calcul peut se modéliser par l'arbre binaire suivant : - + 2 6 3 4 2 4
Exemple d'implémentation C++ class arbre_calcul { enum type_operation {aucun=0,plus='+', moins='-', mult='', div='/'}; struct feuille { type_operation Operateur; double Operande; feuille f_gauche; feuille f_droite; double Valeur() const; }; typedef feuille pfeuille; pfeuille racine; double Valeur() const; Département Informatique 5
Effectuer le calcul En utilisant un algorithme récursif, effectuer le calcul est simple. En effet, la valeur d'une racine (d'un sous-arbre) se déduit directement : De l'opérateur contenu dans la racine De la valeur de l'opérande gauche De la valeur de l'opérande droite On voit bien que l'on a besoin d'une méthode Valeur() qui va renvoyer : Soit la valeur contenue dans la feuille si c'est un nombre Soit le résultat d'un calcul si c'est un opérateur 6
double arbre_calcul::valeur() const { double val=0; if(racine) val = racine->valeur(); return val; } La récursivité nous permet le parcours simple de l'arborescence double feuille::valeur() const { double val=0; switch(operateur) { case aucun: val=operande; break; case plus: val=gauche->valeur() + droite->valeur();break; //... return val; } 7
Le "lancement" du calcul est donc extrêmement simple, du fait de la structure de l'arbre binaire et de l'utilisation d'un algorithme récursif pour Valeur() La création de l'arbre est un peu plus complexe, il faut bien évidemment gérer les priorités relatives des 4 opérateurs. Si l'on souhaite gérer des parenthèses, la création de l'arbre se complexifie d'avantage, mais pas le calcul. En effet, une expression entre parenthèses est un sous-arbre. 8
Algorithmes d'ajout (sans parenthèses) Une expression commence obligatoirement par une opérande. Se trouve ensuite un enchaînement opérateur-opérande L'opérateur joue un rôle de "pivot" dans l'analyse de l'expression Suivant celui-ci, sa priorité par rapport au précédent, l'ajout dans l'arbre ne se fera pas de la même manière. Priorité + - / + = = < < - = = < < > > = = / > > = = 9
103-2 Cas n 1 : ajout à priorité inférieure On ajoute le nouvel opérateur comme une racine et on prend l'ancien à gauche et l'opérande à droite 10 3-2 10 3 10
Cas n 2 : ajout à priorité supérieure 10 + 43 10 + 4 On remplace la feuille de droite par le nouvel opérateur, qui prendra à gauche l'ancienne opérande et à droite la nouvelle opérande + 10 4 3 11
Cas 3 : ajout à priorité égale 3 + 4-2 La cas est identique au cas n 1 + - 3 4 + 2 3 4 12
Gestion des parenthèses 3(4+2(1-142)) Le principal problème avec les parenthèses est la détection des sous-expressions complètes. On remarque que l'ouverture d'une parenthèse démarre une expression (donc un sous-arbre) et que la fermeture la termine. La première parenthèse fermante correspond à la dernière parenthèse ouvrante : on remarque que l'utilisation d'une pile peut simplifier la gestion des parenthèses pour la construction de l'arbre... 13
3(4+2(1-142)) On empile la suite de l'expression 3 + 4-2 Puis on dépile, et on relie les feuilles droites. 1 14 2 14
Prochain cours : Structures de données partie 4 arbres non binaires tables de hachage Bonnes vacances! 15