La structure d'arbre étend le concept de liste en admettant plusieurs éléments suivants plutôt qu'un seul.
Cela s'accompagne d'un changement de vocabulaire
Les élément sont stockés dans des structures appelées noeuds.
class Noeud:
def __init__(self,valeur):
self.etiquette = valeur
self.enfants = []
def ajouter_enfant(self,valeur):
self.enfants.append(Noeud(valeur))
return self.enfants[len(self.enfants)-1]
def __str__(self):
return "{}".format(self.etiquette)
Construisons manuellement un tel arbre
racine = Noeud('A')
b = racine.ajouter_enfant('B')
c = racine.ajouter_enfant('C')
d = racine.ajouter_enfant('D')
e = racine.ajouter_enfant('E')
f = b.ajouter_enfant('F')
g = b.ajouter_enfant('G')
h = d.ajouter_enfant('H')
i = e.ajouter_enfant('I')
j = e.ajouter_enfant('J')
k = e.ajouter_enfant('K')
Affichons cet arbre avec la racine A
à gauche
import include.helpers as h
h.afficher_arbre(racine)
Il est indispensable de pouvoir atteindre une et une seule fois tous les éléments d'un arbre. Pour cela, la méthode la plus simple est le parcours en profondeur.
Il correspond à l'ordre de succession au trône dans la plupart des monarchies européennes: la primogéniture, i.e.
Il se définit récursivement
def parcoursEnProfondeur(R,action):
if R:
action(R)
for r in R.enfants:
parcoursEnProfondeur(r,action)
h.afficher_arbre(racine)
# Effectuez le parcours en profondeur de cet arbre
def afficher(R): print(R, end=" ")
parcoursEnProfondeur(racine, afficher)
A B F G C D H E I J K
Notons qu'il s'agit là d'un parcours pré-ordonné: l'action sur la racine s'effectue avant l'action sur ses enfants. On peut aussi définir un parcours post-ordonné
def parcoursPostOrdonne(R,action):
if R:
for r in R.enfants:
parcoursPostOrdonne(r,action)
action(R)
h.afficher_arbre(racine)
# Parcourez l'arbre en profondeur et listez les noeuds en post-ordre
parcoursPostOrdonne(racine, afficher)
F G B C H D I J K E A
L'affichage indenté effectue un parcours en profondeur tout en notant la profondeur de récursion.
Il affiche un noeud par ligne, décalé de cette profondeur
def affichage_indente(R,profondeur):
if R:
print(" "*profondeur*3,R)
for r in R.enfants:
affichage_indente(r,profondeur+1)
affichage_indente(racine,0)
A B F G C D H E I J K
L'affichage sous forme de liste imbriquée utilise
def affichage_listes_imbriquees(R):
if R:
print(R,end="")
if len(R.enfants) > 0:
print("(",end="")
for i,r in enumerate(R.enfants):
if i > 0: print(",",end="")
affichage_listes_imbriquees(r)
print(")",end ="")
h.afficher_arbre(racine)
# Représentez cet arbre sous forme de listes imbriquées
affichage_listes_imbriquees(racine)
A(B(F,G),C,D(H),E(I,J,K))
Le parcours en largeur correspond lui à l'ordre de succession adelphique, comme par exemple pour le trône d'Arabie Saoudite.
from queue import Queue
def parcoursEnLargeur(R):
Q = Queue()
Q.put(R)
while not Q.empty():
n = Q.get()
print(n, end=" ")
for c in n.enfants:
Q.put(c)
h.afficher_arbre(racine)
# Effectuez le parcours en largeur de cet arbre
parcoursEnLargeur(racine)
A B C D E F G H I J K
Degré d'un noeud :=
nombre de ses enfants
def degreNoeud(R):
if R: return len(R.enfants)
else: return 0
Degré d'un arbre :=
degré maximum de ses noeuds
def degreArbre(R):
d = degreNoeud(R)
if R:
for c in R.enfants:
d = max(d,degreArbre(c))
return d
h.afficher_arbre(racine)
# Quel est le degré de cet arbre ?
degreArbre(racine)
4
noeuds n'ayant pas d'enfants
def feuilles(R):
if R:
if len(R.enfants) == 0: print(R, end=" ")
for c in R.enfants:
feuilles(c)
h.afficher_arbre(racine)
# Quelles sont les feuilles de cet arbre ?
feuilles(racine)
F G C H I J K
noeuds ayant des enfants
def noeuds_internes(R):
if R:
if len(R.enfants) != 0: print(R, end=" ")
for c in R.enfants:
noeuds_internes(c)
h.afficher_arbre(racine)
# Quels sont les noeuds internes de cet arbre ?
noeuds_internes(racine)
A B D E
noeud parent et ses ancêtres jusqu'à la racine qui n'a pas de parent.
def ancetres(R,val):
if R:
if R.etiquette == val:
return True
else:
for e in R.enfants:
if(ancetres(e,val)):
print(R, end=" ")
return True
return False
h.afficher_arbre(racine)
# Quels sont les ancêtre de J
ancetres(racine,'J')
E A
True
ancetres(racine,'Z')
False
plus grand nombre de noeuds sur le chemin allant d'une feuille à la racine
def hauteur(R):
if R:
h = 1
for c in R.enfants:
h = max(h,hauteur(c)+1)
return h
else:
return 0
h.afficher_arbre(racine)
# Quelle est la hauteur de cet arbre ?
hauteur(racine)
3
nombre de noeuds de l'arbre
def taille(R):
if R:
t = 1
for c in R.enfants:
t += taille(c)
return t
else:
return 0
h.afficher_arbre(racine)
# Quelle est la taille de cette arbre ?
taille(racine)
11
© Olivier Cuisenaire, 2018 |