Beaucoup de blabla dans cette partie car on y présente des variantes de la classe AB utilisée lors de vos séances de TP.
La classe basique utilisée sur ce site
Nous avons pour le moment utilisé un modèle objet très simple basé sur une seule classe nommée AB.
1.0 Arbre binaire : modèle objet où AB NON VIDE et Noeud sont des alias
C'est le modèle utilisé sur la plupart des TP de ce site.
Remarques générales
Avec ce modèle, il n'y a pas de différence entre un Noeud et un Arbre Binaire NON VIDE : ce sont deux alias vers le même contenu mémoire.
La classe ne contient que trois attributs : valeur, gauche et droite.
IMPORTANT : le seul cas où on peut envoyer une valeur None est pour l'Arbre Binaire VIDE.
1
2
3
4
5
6
7
classAB:"""Implémentation d'un Arbre Binaire sous forme objet simple"""def__init__(self,valeur,gauche,droite):self.v=valeur# valeur attribuée à la racineself.g=gauche# Référence du sous-arbre gauche ou None si on atteint un Arbre Binaire Videself.d=droite# Référence du sous-arbre droite ou None si on atteint un Arbre Binaire Vide
"""Module implémentant un Arbre Binaire (AB) avec un modèle objetCoûts et prototypes des primitives disponibles :[cst] nv_ABV() -> 'AB VIDE'[cst] nv_AB(valeur:'Element', g:'AB', d:'AB') -> 'AB NON VIDE'[cst] est_ABV(arbre:'AB') -> bool[cst] racine(arbre:'AB NON VIDE') -> 'Noeud'[cst] gauche(arbre:'AB NON VIDE') -> 'AB'[cst] droite(arbre:'AB NON VIDE') -> 'AB'[cst] contenu(noeud:'Noeud') -> 'Element'"""# Déclaration de la classe ABclassAB:"""Implémentation d'un Arbre Binaire"""def__init__(self,valeur,gauche,droite):self.v=valeurself.g=gaucheself.d=droitedefrelier_a_gauche(self:'AB NON VIDE',sous_arbre:'AB'):"""Méthode qui définit sous_arbre comme le sous-arbre gauche de l'arbre actif"""self.g=sous_arbredefrelier_a_droite(self:'AB NON VIDE',sous_arbre:'AB'):"""Méthode qui définit sous_arbre comme le sous-arbre droite de l'arbre actif"""self.d=sous_arbredefdefinir_donnees_racine(self:'AB',element:'Element NON VIDE'):"""Méthode qui place l'élément NON VIDE en tant que racine de l'arbre"""self.v=elementdefvider(self:'AB'):"""Méthode qui transforme l'arbre en AB VIDE"""self.v=Noneself.g=Noneself.d=None# Fonctions d'interface (accessibles de l'extérieur)defcontenu(noeud:'Noeud')->'Element':"""Renvoie le contenu associé au noeud fourni"""returnnoeud.vdefnv_ABV()->'AB VIDE':"""Renvoie un nouvel Arbre Binaire Vide"""returnAB(None, None, None)
defnv_AB(valeur:'Element',g:'AB',d:'AB')->'AB NON VIDE':"""Renvoie un nouvel Arbre Binaire dont la racine porte valeur et qui mène aux sous-arbres g et d"""returnAB(valeur,g,d)defest_ABV(arbre:'AB')->bool:"""Prédicat qui renvoie True si l'arbre est vide"""returnarbre.visNoneandarbre.gisNoneandarbre.disNonedefracine(arbre:'AB NON VIDE')->'Noeud':"""Renvoie le noeud-racine de l'Arbre Binaire NON VIDE"""returnarbre# ici arbre et racine sont des aliasdefgauche(arbre:'AB NON VIDE')->'AB':"""Renvoie le sous-arbre gauche de l'Arbre Binaire NON VIDE"""returnarbre.gdefdroite(arbre:'AB NON VIDE')->'AB':"""Renvoie le sous-arbre droite de l'Arbre Binaire NON VIDE"""returnarbre.d# Programme de test du moduleif__name__=="__main__":ad=nv_AB("D", nv_ABV(), nv_ABV())af=nv_AB("F",ad, nv_ABV())ae=nv_AB("E",nv_ABV(), af)ah=nv_AB("H", nv_ABV(), nv_ABV())ag=nv_AB("G",nv_ABV(), ah)ab=nv_AB("B", nv_ABV(), nv_ABV())ac=nv_AB("C",ag,ab)aa=nv_AB("A",ac,ae)print(contenu(racine(gauche(aa))))
Génération d'arbres et de noeuds
On donne à chaque fois l'utilisation directe du modèle suivi de l'utilisation des fonctions-primitives founies dans le module.
Un Arbre Binaire VIDE est créé avec
AB(None, None, None) nv_ABV()
Un Arbre Binaire NON VIDE est créé avec
AB(valeur, arbre_gauche, arbre_droite) nv_AB(valeur, arbre_gauche, arbre_droite)
Un Arbre Binaire NON VIDE avec un sous-arbre gauche vide est créé avec
AB(valeur, AB(None, None, None), arbre_droite) nv_AB(valeur, nv_ABV(), arbre_droite)
Un Arbre Binaire NON VIDE avec un sous-arbre droite vide est créé avec
AB(valeur, arbre_gauche, AB(None, None, None)) nv_AB(valeur, arbre_droite, nv_ABV())
Une feuille est créée avec
AB(valeur, AB(None, None, None), AB(None, None, None)) nv_AB(valeur, nv_ABV(), nb_ABV())
Variante 1 : fournir des valeurs par défaut
01° Créer des arbres ou des feuilles nécessite à chaque fois d'indiquer les sous-arbres, même s'ils sont des arbres binaires vides.
On peut simplifier l'écriture en utilisant les valeurs par défaut : voir la ligne 4.
1
2
3
4
5
6
7
classAB:"""Implémentation d'un Arbre Binaire sous forme objet simple"""def__init__(self,valeur=None,gauche=None,droite=None):self.v=valeur# valeur attribuée à la racineself.g=gauche# Référence du sous-arbre gauche ou None si on atteint un Arbre Binaire Videself.d=droite# Référence du sous-arbre droite ou None si on atteint un Arbre Binaire Vide
Questions
A quoi correspondent les valeurs None qu'on trouve sur la ligne 4 de cette variante de la classe AB ?
Comment peut-on utiliser le constructeur pour créer une Arbre VIDE de façon plus courte ?
Comment peut-on utiliser le constructeur pour créer une Feuille ?
...CORRECTION...
Ce sont des valeurs par défaut, utilisées uniquement si on réalise un appel sans envoyer des valeurs pour ces paramètres.
Arbre vide : AB() qui sera transformé en AB(None, None, None) pour compléter les valeurs manquantes.
Feuille : AB(valeur, AB(), AB()) qui sera transformé en AB(valeur, AB(None, None, None), AB(None, None, None)) pour compléter les valeurs manquantes.
Le bilan suivant est à lire en diagonale uniquement : il est là surtout pour vous permettre de reprendre le code si vous en avez besoin en projet.
1.1 Arbre binaire : modèle objet avec valeur par défaut
Remarques
Créer des arbres ou des feuilles nécessite à chaque fois d'indiquer les sous-arbres, même s'ils sont des arbres binaires vides.
On peut simplifier l'écriture en utilisant les valeurs par défaut : voir la ligne 4.
1
2
3
4
5
6
7
classAB:"""Implémentation d'un Arbre Binaire sous forme objet simple"""def__init__(self,valeur=None,gauche=None,droite=None):self.v=valeur# valeur attribuée à la racineself.g=gauche# Référence du sous-arbre gauche ou None si on atteint un Arbre Binaire Videself.d=droite# Référence du sous-arbre droite ou None si on atteint un Arbre Binaire Vide
Cela veut dire qu'on peut se permettre de ne pas envoyer certaines valeurs. Dans ce cas, elles seront initialisées à None comme indiqué dans le code.
Génération d'arbres et de noeuds : plus facile
On donne à chaque fois l'utilisation directe du modèle suivi de l'utilisation des fonctions-primitives founies dans le module.
Un Arbre Binaire VIDE est créé avec
AB() nv_ABV()
Un Arbre Binaire NON VIDE est créé avec
AB(valeur, arbre_gauche, arbre_droite) nv_AB(valeur, arbre_gauche, arbre_droite)
Un Arbre Binaire NON VIDE avec un sous-arbre gauche vide est créé avec
AB(valeur, AB(), arbre_droite) nv_AB(valeur, nv_ABV(), arbre_droite)
Un Arbre Binaire NON VIDE avec un sous-arbre droite vide est créé avec
AB(valeur, arbre_gauche, AB()) nv_AB(valeur, arbre_droite, nv_ABV())
Une feuille est créée avec
AB(valeur, AB(), AB()) nv_AB(valeur, nv_ABV(), nb_ABV())
"""Module implémentant un Arbre Binaire (AB) avec un modèle objetCoûts et prototypes des primitives disponibles :[cst] nv_ABV() -> 'AB VIDE'[cst] nv_AB(valeur:'Element', g:'AB', d:'AB') -> 'AB NON VIDE'[cst] est_ABV(arbre:'AB') -> bool[cst] racine(arbre:'AB NON VIDE') -> 'Noeud'[cst] gauche(arbre:'AB NON VIDE') -> 'AB'[cst] droite(arbre:'AB NON VIDE') -> 'AB'[cst] contenu(noeud:'Noeud') -> 'Element'"""# Déclaration de la classe ABclassAB:"""Implémentation d'un Arbre Binaire"""def__init__(self,valeur=None,gauche=None,droite=None):self.v=valeurself.g=gaucheself.d=droite
# Le reste est inchangé
Variante 2 : uniquement les Noeuds
Dans certains sujets, on ne définit qu'une classe Noeud. On ne peut donc pas gérer directement l'arbre binaire vide puisqu'il ne possède pas de noeud par définition...
1.2 Arbre binaire NON VIDE : Noeud avec un modèle objet
Remarques
Un Arbre binaire possède une valeur de racine et possède toujours deux sous-arbres binaires (qui peuvent être un objet arbre VIDE AB(), pas None directement).
Un Noeud d'arbre binaire possède une valeur et possède au maximum deux enfants : ils sont donc des Noeuds ou rien. Cette fois, on pourra utiliser None pour indiquer l'absence de noeud enfant.
1
2
3
4
5
6
7
classNoeud:"""Implémentation d'unNoeud sous forme objet simple"""def__init__(self,valeur=None,enfant_gauche=None,enfant_droite=None):self.v=valeur# valeur attribuée à la racineself.g=enfant_gauche# Référence du noeud à gauche, ou Noneself.d=enfant_droite# Référence du noeud à droite, ou None
Génération de noeuds
Un Arbre Binaire VIDE : impossible avec la classe Noeud, à moins de considérer qu'un triplet d'attributs Noeud(None, None, None) encode l'arbre vide. Mais c'est "bizarre" de créer un Noeud pour un arbre vide, qui par définition ne contient pas de Noeud justement.
La plupart du temps, avec cette implémentation, on prend None comme valeur d'encodage de l'arbre binaire VIDE. Simple sur les arbres qui n'évoluent pas mais choix embêtant si on doit insérer/supprimer régulièrement.
Un Noeud est créé avec
Noeud(valeur, noeud_gauche, noeud_droite)
Un Noeud avec uniquement un enfant droite:
Noeud(valeur, None, noeud_droite)
Un Noeud avec uniquement un enfant gauche :
Noeud(valeur, enfant_gauche, None) si valeurs par défaut
Une feuille est créée avec
Noeud(valeur, None, None)
Variante 3 : une classe AB et une classe Noeud
On peut revenir à quelque chose de proche du type abstrait en distinguant dans le code les arbres et les noeuds.
1.3 Arbre binaire et Noeud avec un modèle objet
Remarques générales
Cette fois l'arbre NON VIDE n'est pas un alias de son Noeud-Racine mais une référence vers son Noeud racine.
L'arbre binaire VIDE et NON VIDE sont définis comme des instances de la classe AB.
Un noeud est une instance de la classe Noeud.
Implémentation
1 2 3 4 5 6 7 8 91011121314151617181920
classNoeud:"""Implémentation d'un Noeud sous forme objet simple"""def__init__(self,valeur=None,enfant_gauche=None,enfant_droite=None):self.v=valeur# valeur attribuée à la racineself.g=enfant_gauche# Référence du noeud à gauche, ou Noneself.d=enfant_droite# Référence du noeud à droite, ou NoneclassAB:"""Implémentation d'un AB VIDE ou NON VIDE sous forme objet"""def__init(self,racine=None):self.r=racine# une instance de Noeud si NON VIDE ou None si VIDEif__name__=="__main__":arb_vide=AB()# Ici on envoie None par défautc=Noeud("C")# c est une feuille ne contenant que "C"b=Noeud("B")# b est une feuille ne contenant que "B"a=Noeud("A",b,c)# a est un Noeud contenant "A" et menant à b et carb_a=AB(a)# arb_a est un Arbre Binaire de racine a
Mini variante : triplet (g, r, d) plutôt que (r, g, d)
On note parfois le triplet en plaçant la valeur de la racine au milieu.
02° Une expression arithmétique ne comportant que les quatre opérations +, -, *, ÷ peut être représentée sous forme d’arbre binaire. Les nœuds internes sont des opérateurs et les feuilles sont des nombres.
Dans un tel arbre, la disposition des nœuds joue le rôle des parenthèses.
En parcourant en profondeur infixe l’arbre binaire ci-dessus, on retrouve l’expression notée habituellement :
(3 * (8 + 7)) - (2 + 1)
La classe Expr permet d’implémenter une structure d’arbre binaire pour représenter de telles expressions.
Compléter la méthode récursive infixe qui renvoie une chaîne de caractères contenant des parenthèses représentant l’expression arithmétique sur laquelle on l’applique.
classExpr:"""Classe implémentant un arbre d'expression."""def__init__(self,g:'None|Expr',v:'int|str',d:'None|Expr'):"""un objet Expr possède 3 attributs """self.gauche=g# la sous-expression gaucheself.valeur=v# valeur de l'étiquette, opérande ou nombreself.droite=d# la sous-expression droitedefest_une_feuille(self)->bool:"""renvoie True SSI le noeud est une feuille"""returnself.gaucheisNoneandself.droiteisNonedefinfixe(self)->str:"""renvoie la représentation infixe de l'expression"""s=...ifself.gaucheisnotNone:s='('+s+....infixe()s=s+...if...isnotNone:s=s+...+...returns
Exemples d'utilisation (attention, dans les vrais sujets Type 2 les types ne sont presque jamais indiqués dans la documentation mais sont retrouvables via les exemples et/ou le code.)
classExpr:"""Classe implémentant un arbre d'expression."""def__init__(self,g:'None|Expr',v:'int|str',d:'None|Expr'):"""un objet Expr possède 3 attributs """self.gauche=g# la sous-expression gaucheself.valeur=v# valeur de l'étiquette, opérande ou nombreself.droite=d# la sous-expression droitedefest_une_feuille(self)->bool:"""renvoie True SSI le noeud est une feuille"""returnself.gaucheisNoneandself.droiteisNonedefinfixe(self)->str:"""renvoie la représentation infixe de l'expression"""s=""ifself.gaucheisnotNone:s='('+s+self.gauche.infixe()s=s+str(self.valeur)
ifself.droiteisnotNone:s=s+self.droite.infixe()+")"returns
03° Un arbre binaire est soit vide, représenté en Python par la valeur None, soit un nœud, contenant une étiquette et deux sous-arbres gauche et droit et représenté par une instance de la classe Noeud donnée ci-dessous.
1
2
3
4
5
6
7
classNoeud:"""Implémentation d'un Noeud sous forme objet simple"""def__init__(self,valeur,enfant_gauche,enfant_droite):self.v=valeur# valeur attribuée à la racineself.g=enfant_gauche# Référence du noeud à gauche, ou Noneself.d=enfant_droite# Référence du noeud à droite, ou None
L’arbre NON VIDE ci-dessous sera donc implémenté de la manière suivante, en considérant qu'il n'est qu'un alias vers son noeud-racine :
classNoeud:"""Implémentation d'un Noeud sous forme objet simple"""def__init__(self,valeur,enfant_gauche,enfant_droite):self.v=valeur# valeur attribuée à la racineself.g=enfant_gauche# Référence du noeud à gauche, ou Noneself.d=enfant_droite# Référence du noeud à droite, ou Nonedeftaille(a:'Noeud|None')->int:"""Renvoie la taille de l'arbre NON VIDE dont la racine est a ou d'un arbre VIDE"""ifaisNone:# si l'arbre est VIDE, presque équivalent de a == Nonereturn0else:return1+taille(a.g)+taille(a.d)defhauteur(a:'Noeud|None')->int:"""Renvoie la hauteur de l'arbre NON VIDE dont la racine est a ou d'un arbre VIDE"""ifaisNone:# si l'arbre est VIDE, presque équivalent de a == Nonereturn-1else:return1+max(hauteur(a.g),hauteur(a.d))if__name__=="__main__":a=Noeud(1,Noeud(4,None,None),Noeud(0,None,Noeud(7,None,None)))n=taille(a)assertn==4asserttaille(None)==0print('Tests taille : ok')h=hauteur(a)asserth==2asserthauteur(None)==-1print('Tests hauteur : ok')
04° Un arbre binaire est soit vide, représenté en Python par la valeur None, soit un nœud, contenant une étiquette et deux sous-arbres gauche et droite et représenté par une instance de la classe Noeud donnée ci-dessous.
classNoeud:"""Classe représentant un noeud d'un arbre binaire"""def__init__(self,etiquette,gauche,droit):"""Crée un noeud de valeur etiquette avec gauche et droit comme fils."""self.etiquette=etiquetteself.gauche=gaucheself.droit=droitdefparcours(arbre,liste):"""parcours récursivement l'arbre en ajoutant les étiquettes de ses noeuds à la liste passée en argument en ordre infixe."""ifarbre!=None:parcours(arbre.gauche,liste)liste.append(arbre.etiquette)parcours(arbre.droit,liste)definsere(arbre,cle):"""insere la cle dans l'arbre binaire de recherche représenté par arbre. Renvoie l'arbre modifié."""ifarbre==None:returnNoeud(cle,None,None)# creation d'une feuilleelse:if...:arbre.gauche=insere(arbre.gauche,cle)else:arbre.droit=...returnarbre
La fonction récursive parcours() renvoie la liste des étiquettes des nœuds de l’arbre implémenté par l’instance arbre dans l’ordre du parcours en profondeur infixe à partir d’une liste vide passée en argument.
Compléter le code de la fonction insere() qui prend en argument un arbre binaire de recherche arbre représenté ainsi et une étiquette cle (non présente dans l’arbre, pas de doublon) et qui :
renvoie une nouvelle feuille d’étiquette cle s’il est vide ;
renvoie l’arbre après l’avoir modifié en insérant cle sinon ;
garantit que l’arbre ainsi complété soit encore un arbre binaire de recherche.
Tester ensuite ce code en utilisant la fonction parcours() et en insérant successivement des
nœuds d’étiquette 1, 4, 6 et 8 dans l’arbre binaire de recherche représenté ci- dessous :
classNoeud:"""Classe représentant un noeud d'un arbre binaire"""def__init__(self,etiquette,gauche,droit):"""Crée un noeud de valeur etiquette avec gauche et droit comme fils."""self.etiquette=etiquetteself.gauche=gaucheself.droit=droitdefparcours(arbre,liste):"""parcours récursivement l'arbre en ajoutant les étiquettes de ses noeuds à la liste passée en argument en ordre infixe."""ifarbre!=None:parcours(arbre.gauche,liste)liste.append(arbre.etiquette)parcours(arbre.droit,liste)definsere(arbre,cle):"""insere la cle dans l'arbre binaire de recherche représenté par arbre. Renvoie l'arbre modifié."""ifarbre==None:returnNoeud(cle,None,None)# creation d'une feuilleelse:ifcle<arbre.etiquette:arbre.gauche=insere(arbre.gauche,cle)else:arbre.droit=insere(arbre.droit,cle)returnarbreif__name__=="__main__":n7=Noeud(7,None,None)n3=Noeud(3,None,None)n2=Noeud(2,None,n3)n5=Noeud(5,n2,n7)t1=[]parcours(n5,t1)n5=insere(n5,1)n5=insere(n5,4)n5=insere(n5,6)n5=insere(n5,8)t2=[]parcours(n5,t2)print(t1)print(t2)
Puisqu'un arbre est un triplet (g,v,d), on peut utiliser le type tuple pour les implémenter.
On obtient alors un type immuable bien entendu.
05° Dans cet exercice, on considère des arbres binaires de recherche qui sont :
soit l’arbre vide identifié par None ;
soit un nœud, contenant une clé et deux sous-arbres gauche et droit et représenté par un triplet (g, v, d) où g et d sont les sous-arbres gauche et droite et v la clé.
L'arbre binaire de recherche abr1 ci-dessus est créé par le code python suivant :
Écrire une fonction récursiveinsertion_abr(a, cle) qui prend en paramètres une clé cle et un arbre binaire de recherche a , et qui renvoie un arbre binaire de recherche dans lequel cle a été insérée.
Dans le cas où cle est déjà présente dans a, la fonction renvoie l’arbre a inchangé. On ne gère donc pas ici les valeurs identiques multiples.
"""AB NON VIDE : tuple (g, v, d)AB VIDE : NoneOn ne distingue donc pas l'AB NON VIDE de son Noeud-racine."""definsertion_abr(a:'AB NON VIDE',cle:'Element')->'AB NON VIDE':ifcle<a[1]:# si la clé est plus petite que l'étiquette de l'arbreifa[0]isNone:# si l'emplacement à gauche est disponiblenouvel_arbre=(None,cle,None)# on crée une feuilleelse:nouvel_arbre=insertion_abr(a[0],cle)# on crée récursivement l'arbrereturn(nouvel_arbre,a[1],a[2])elifcle>a[1]:# sinon, si la clé est plus grandeifa[2]isNone:# si l'emplacement droite est disponiblenouvel_arbre=(None,cle,None)# on crée une feuilleelse:nouvel_arbre=insertion_abr(a[2],cle)# on crée récursivement l'arbrereturn(a[0],a[1],nouvel_arbre)else:returna# on renvoie l'arbre inchangéif__name__=="__main__":n0=(None,0,None)n3=(None,3,None)n2=(None,2,n3)abr1=(n0,1,n2)print(insertion_abr(abr1,4))print(insertion_abr(abr1,-5))print(insertion_abr(abr1,2))
06° Un arbre binaire est soit vide, représenté en Python par la valeur None, soit un nœud représenté par un triplet (g, x, d) où x est l’étiquette du nœud et g et d sont les sous- arbres gauche et droite.
On souhaite écrire une fonction parcours_largeur() qui prend en paramètre un arbre binaire et qui renvoie la liste des étiquettes des nœuds de l’arbre parcourus en largeur.
Remarques
Pour la File, faire soit une File du pauvre (avec du append(x) constant et pop(0) linéaire) ou importer collections et son type deque (avec du append(x) constant et popleft() constant).
Attention à bien lire le sujet : on doit renvoyer un tableau des noeuds rencontrés, pas juste réaliser un affichage.
"""AB NON VIDE : tuple (g, v, d)AB VIDE : NoneOn ne distingue donc pas l'AB NON VIDE de son Noeud-racine."""defparcours_largeur(ab:'AB')->list:"""Renvoie la liste des clés rencontrées"""# Implémentation avec une mauvaise file, on utilse pop(0)t=[]# on crée le tableau des étiquettes rencontréesifabisnotNone:# ou if not(a is None):f=[]# on crée une filef.append(ab)whilef!=[]:ab=f.pop(0)# on défile l'arbret.append(ab[1])# on rajoute sa clé dans le tableauifab[0]isnotNone:# si le sous-arbre gauche n'est pas videf.append(ab[0])ifab[2]isnotNone:# si le sous-arbre droite n'est pas videf.append(ab[2])returntif__name__=="__main__":arbre=(((None,1,None),2,(None,3,None)),4,((None,5,None),6,(None,7,None)))t=parcours_largeur(arbre)print(t)
07° Dans cet exercice, un arbre binaire de caractères non vide est stocké sous la forme d’un dictionnaire où les clefs sont les caractères des nœuds de l’arbre et les valeurs, pour chaque clef, la liste des caractères des fils gauche et droit du nœud. On utilise la valeur '' pour représenter un fils vide.
Écrire une fonction récursivetaille() prenant en paramètres un arbre binaire arbre NON VIDE sous la forme d’un dictionnaire et un caractère lettre qui est la valeur du sommet de l’arbre, et qui renvoie la taille de l’arbre à savoir le nombre total de nœuds.
On observe que, par exemple, arbre[lettre][0], respectivement arbre[lettre][1], permet d’atteindre la clé du sous-arbre gauche, respectivement droite, de l’arbre de sommet lettre.
"""AB NON VIDE : { 'A': ['', ''] } pour représenter une feuille par exemple"""deftaille(ab:'AB NON VIDE',cle:'str')->int:"""Renvoie la taille de l'arbre binaire NON VIDE dont on donne la clé de la racine"""ifcle=='':# pas de clé donc il n'y a pas de noeudreturn0else:return1+taille(ab,ab[cle][0])+taille(ab,ab[cle][1])if__name__=="__main__":a={'F':['B','G'],'B':['A','D'],'A':['',''],'D':['C','E'],'C':['',''],'E':['',''],'G':['','I'],'I':['','H'],'H':['','']}print(taille(a,'F'))