Il est possible de retrouver la topologie exacte d'un arbre binaire à partir de deux de ses parcours parmi les trois parcours en profondeur
En effet, ces parcours nous donnent des renseignements complémentaires. Pour un arbre de racine R,
R, R.gauche, le sous-arbre de R.gauche, R.droite, le sous arbre de R.droiteR.gauche y compris R.gauche, la racine R, le sous-arbre de R.droite y compris R.droiteR.gauche, R.gauche, le sous arbre de R.droite, R.droite et enfin RRecouper ces informations nous permet de reconstruire l'arbre
Considérons l'arbre suivant
class Noeud:
def __init__(self,val):
self.etiquette = val
self.gauche = None
self.droite = None
def __str__(self):
return self.etiquette.__str__()
racine = a = Noeud('A')
a.gauche = b = Noeud('B'); a.droite = c = Noeud('C')
b.gauche = d = Noeud('D'); b.droite = e = Noeud('E')
c.gauche = f = Noeud('F'); f.gauche = g = Noeud('G')
import include.helpers as h
h.afficher_arbre_binaire(racine)
Les fonctions suivantes nous donnent les parcours sous forme de liste
def preordonne(R):
if R:
p = [ R.etiquette ]
p.extend( preordonne(R.gauche))
p.extend( preordonne(R.droite))
return p
else:
return [ ]
pre = preordonne(racine); print(pre)
['A', 'B', 'D', 'E', 'C', 'F', 'G']
def symetrique(R):
if R:
p = symetrique(R.gauche)
p.append(R.etiquette)
p.extend( symetrique(R.droite))
return p
else:
return [ ]
sym = symetrique(racine); print(sym)
['D', 'B', 'E', 'A', 'G', 'F', 'C']
def postordonne(R):
if R:
p = postordonne(R.gauche)
p.extend( postordonne(R.droite))
p.append( R.etiquette )
return p
else:
return [ ]
post = postordonne(racine); print(post)
['D', 'E', 'B', 'G', 'F', 'C', 'A']
# Reconstruisons l'arbre à partir de ses parcours pré-ordonné et symétrique
print(pre); print(sym)
['A', 'B', 'D', 'E', 'C', 'F', 'G'] ['D', 'B', 'E', 'A', 'G', 'F', 'C']
# Le parcours pré-ordonné nous donne la racine
etiquette_racine = pre[0]; print("Racine: ",etiquette_racine)
Racine: A
# La position de la racine dans le parcours symétrique nous donne les 2 sous arbres
p = sym.index(etiquette_racine)
print("R.gauche: pre =",pre[1:p+1],", sym =",sym[0:p])
print("R.droite: pre =",pre[p+1:],", sym =",sym[p+1:])
R.gauche: pre = ['B', 'D', 'E'] , sym = ['D', 'B', 'E'] R.droite: pre = ['C', 'F', 'G'] , sym = ['G', 'F', 'C']
il suffit de refaire le même raisonnement pour les sous-arbres jusqu'à obtenir un parcours de 0 ou 1 élément
L'algorithme récursif s'écrit
def arbre_depuis_parcours(pre,sym):
assert(len(pre) == len(sym))
if len(pre) == 0:
return None
position_racine_dans_pre = 0
etiquette_racine = pre[position_racine_dans_pre]
i = position_racine_dans_sym = sym.index(etiquette_racine)
R = Noeud(pre[0])
R.gauche = arbre_depuis_parcours( pre[1:i+1], sym[0:i] )
R.droite = arbre_depuis_parcours( pre[i+1:], sym[i+1:] )
return R
print(pre); print(sym)
R = arbre_depuis_parcours(pre,sym)
h.afficher_arbre_binaire(R)
['A', 'B', 'D', 'E', 'C', 'F', 'G'] ['D', 'B', 'E', 'A', 'G', 'F', 'C']
|
|
© Olivier Cuisenaire, 2018 |