1 Représentation n-aire d`expressions arithmétiques 2

Université Claude Bernard - Lyon 1
Algorithmique, Programmation et Complexité - LIF9
Licence Sciences et Technologies - L3
Semestre de printemps
TP - Arbres n-aires, expressions arithmétiques
1
Représentation n-aire d’expressions arithmétiques
Le but est de représenter à l’aide d’arbres n-aires des expressions mathématiques composées uniquement d’entiers, d’additions et de multiplications. Dans un arbre n-aire, chaque nœud peut avoir de 0 à n
fils. Par exemple, l’arbre correspondant à l’expression (6 + 5) ∗ (−2) ∗ (8 + (12 ∗ 3) + (−9)) ∗ 7 est :
Il s’agit d’une représentation plus générale (et un peu plus complexe à implémenter) que les arbres
binaires vus en cours. L’information contenue dans un nœud est donc un nombre entier ou un opérateur
+ ou *. Si le contenu est un nombre entier, le nœud est une feuille. Sinon, c’est-à-dire si le contenu est un
opérateur, le nœud a au moins deux fils. Les structures devront être développées de manière à ce que
chaque nœud puissent avoir un nombre quelconque de liens vers des fils. Par exemple :
2
Implémentation
Comme pour les TPs précédents, vous avez le choix entre le passage de paramètre par pointeur
ou par référence. Développez un module Arbre, avec les fonctions « publiques » listées par la suite.
Elles impliquent d’écrire en plus des fonctions « internes » au module, travaillant sur des nœud s et des
sous-arbres. Chaque fonction publique développée devra être testée dans le programme principal. Votre
programme doit comporter :
1) La définition des structures Arbre et Noeud
2) Une procédure d’initialisation d’un arbre vide et une procédure d’initialisation d’un arbre contenant
un unique entier
procédure initArbreVide(donnée-résultat A : Arbre)
procédure initArbreEntier(donnée-résultat A : Arbre, donnée i : entier)
1
3) Une procédure d’initialisation par recopie
procédure initArbreCopie(donnée-résultat A : Arbre, donnée B : Arbre)
Attention, veillez bien à recopier entièrement l’arbre B, de manière à ce que A et B n’ait aucune adresse
mémoire en commun !
4) Une procédure de destruction d’un arbre complet (destinée à être appelée en fin de programme)
procédure detruitArbre(donnée-résultat A : Arbre)
5)Des procédures d’addition et de multiplication de deux arbres (l’arbre résultat est passé en troisième
paramètre)
procédure additionArbres(donnée A : Arbre, donnée B : Arbre, résultat ApB : Arbre)
procédure multiplicationArbres(donnée A : Arbre, donnée B : Arbre, résultat AfB : Arbre)
Dans le cas général, lorsqu’on additionne (resp. multiplie) deux arbres A et B, le nœud racine de l’arbre
résultat est un opérateur + (resp. *) et possède deux fils qui sont des recopies des arbres A et B. Il existe
un cas particulier pour l’addition, lorsqu’A et/ou B sont eux-mêmes des additions. Dans l’exemple
suivant, A et B ont respectivement p et q sous-arbres fils :
Dans ce cas, au lieu de générer un arbre avec une addition "sur deux étages",
il est plus intéressant de créer directement cet arbre :
Par ailleurs, si A est une addition et B un entier (ou inversement), l’arbre résultat sera une recopie de A
avec un fils supplémentaire recopié de B. Le même raisonnement s’applique évidemment à la multiplication lorsqu’A et B sont eux-mêmes des multiplications.
6) Une fonction qui retourne la valeur entière de l’expression représentée par l’arbre
fonction valeurArbre(donnée A : Arbre)
2
Si l’arbre est un entier, la valeur retournée est l’entier lui-même. Si la racine de l’arbre est une addition
(resp. une multiplication), la valeur retournée est la somme (resp. le produit) des valeurs des sous-arbres.
7) Deux procédures d’affichage d’un arbre.
procédure afficheArbreExpression(donnée A : Arbre)
procédure afficheArbre(donnée A : Arbre)
La première produira l’expression mathématique en notation standard (infixe), tandis que la deuxième
affichera un arbre sur plusieurs niveaux en utilisant judicieusement les espaces. Par exemple, l’arbre
correspondant à l’expression (6 + 5) ∗ (−2) peut être affiché de cette manière :
*
/ \
+
-2
/ \
6
5
8) Bonus. Le produit de deux sommes se développe de la manière suivante :

! q
p
X
X
bj  = a1 b1 + a1 b2 + ...a1 bq
ai 
i=1
j=1
+ a2 b1 + a2 b2 + ...a2 bq
(1)
+ ...
+ ap b1 + ap b2 + ...ap bq
Ecrivez une procédure qui vérifie qu’un arbre passé en donnée est le produit de deux sommes. Si c’est le
cas, la procédure produit un arbre (passé en résultat) représentant la somme développée. Sinon, l’arbre
est recopié. Attention, dans l’exemple précédent, les termes ai et bj sont des expressions quelconques
(donc, des sous-arbres quelconques pour votre procédure de développement)
procédure developpeProduitArbre(donnée A: Arbre, résultat Adev : Arbre)
3
Conditions de rendu
A la date de rendu, vous devrez déposer une archive (formats valables : tar.gz, tgz ou zip) au nom
du ou des étudiant(s) (ex : DUPONT.zip ou DUPONT_DURAND.tar.gz) sur SPIRAL. Le nom du dépôt
et la date limite vous seront communiqués ultérieurement.
Cette archive devra contenir tous les fichiers .c et .h, ainsi que le fichier Makefile. Attention :
– Votre archive NE DOIT PAS contenir de fichiers objets (.o) ni d’exécutable.
– Toute récupération flagrante du code d’autrui sera sanctionnée.
– Votre programme doit pouvoir être compilé sans erreur ni avertissement avec g++ ou gcc, suivant
que vous utilisez la notion de référence ou non (à préciser dans le Makefile), et avec les options
de compilation -Wall -ansi -pedantic
– L’interface de vos modules doit offrir toutes les informations utiles à l’utilisation des types et des
fonctionnalités offertes.
– L’exécution ne doit pas générer de fuite mémoire. Utilisez valgrind pour vérifier que toute la
mémoire allouée est correctement libérée.
3