6.4. TP 1 sur les arbres#

Le but de ce TP est de manipuler des arbres dans des cas simples et d’écrire des algorithmes permettant de les parcourir.

#!pip install --user binarytree

6.4.1. Prise en main de binarytree.#

Créer un arbre avec binarytree.

Un arbre est représenté par une classe Node(), qui dispose d’attributs left et right qui seront des Node().

Recopier et compléter le code suivant.

from binarytree import Node
root = Node(1)
Hide code cell source
root.left = Node(2) # le fils gauche de la racine.
root.right = Node(4) # le fils droit de la racine.
root.left.right = Node(3) # le fils droit du fils gauche de la racine.
root.left.right.right = Node(5)
# le fils droit du fils droit du fils gauche de la …
# Permet de voir notre arbre racine.
print(root)
  ____1
 /     \
2       4
 \
  3
   \
    5

On peut aussi créer l’arbre à partir d’une liste.

from binarytree import build
# Build a tree from list representation
values = [ 7 , 3 , 2 , 6 , 9 , None , 1 , 5 , None ,
10 , 8 , None , None , 11 , None , 12 , 13 , None , None ,14 ]
root = build(values)
print(root)
            __________7
           /           \
          3______       2___
         /       \          \
     ___6        _9         _1
    /           /  \       /
  _5          _10   8     11
 /  \        /
12   13     14

6.4.2. Parcours d’arbre#

Il existe différentes façon de parcourir un arbre.

6.4.2.1. Parcours préfixe d’un arbre#

Observons un premier parcours, avec les fonctions «builtin» du module.

arbre2 = build(values)
print(arbre2,arbre2.preorder)
            __________7
           /           \
          3______       2___
         /       \          \
     ___6        _9         _1
    /           /  \       /
  _5          _10   8     11
 /  \        /
12   13     14
 [Node(7), Node(3), Node(6), Node(5), Node(12), Node(13), Node(9), Node(10), Node(14), Node(8), Node(2), Node(1), Node(11)]

Que peut-on dire de ce parcours ?

Écrire une fonction préfixe qui permet de parcourir un arbre de cette façon.

Hide code cell content
def prefixe(arbre, parcours = []):
    parcours.append(arbre.value)
    if arbre.left != None:
        prefixe(arbre.left, parcours)
    if arbre.right != None:
        prefixe(arbre.right, parcours)
    return parcours

L’appel de cette fonction sera le suivant :

prefixe(arbre2)
[7, 3, 6, 5, 12, 13, 9, 10, 14, 8, 2, 1, 11]

6.4.2.2. Parcours postfixe d’un arbre#

print(arbre2.postorder)
[Node(12), Node(13), Node(5), Node(6), Node(14), Node(10), Node(8), Node(9), Node(3), Node(11), Node(1), Node(2), Node(7)]

Que peut-on dire de ce parcours ?

Coder une fonction récursive postfixe.

Hide code cell content
def postfixe(arbre, parcours = []):
    if arbre.left != None:
        postfixe(arbre.left, parcours)
    if arbre.right != None:
        postfixe(arbre.right, parcours)
    parcours.append(arbre.value)
    return parcours

L’appel de cette fonction sera le suivant :

postfixe(arbre2)
[12, 13, 5, 6, 14, 10, 8, 9, 3, 11, 1, 2, 7]

6.4.2.3. Parcours infixe d’un arbre#

arbre2.inorder
[Node(12),
 Node(5),
 Node(13),
 Node(6),
 Node(3),
 Node(14),
 Node(10),
 Node(9),
 Node(8),
 Node(7),
 Node(2),
 Node(11),
 Node(1)]

Que peut-on dire de ce parcours ?

Coder une fonction récursive infixe.

Hide code cell content
def infixe(arbre, parcours = []):
    if arbre.left != None:
        infixe(arbre.left, parcours)
    parcours.append(arbre.value)
    if arbre.right != None:
        infixe(arbre.right, parcours)
    return parcours

L’appel de cette fonction sera le suivant :

infixe(arbre2)
[12, 5, 13, 6, 3, 14, 10, 9, 8, 7, 2, 11, 1]

6.4.2.4. Parcours par niveau#

arbre2.levelorder
[Node(7),
 Node(3),
 Node(2),
 Node(6),
 Node(9),
 Node(1),
 Node(5),
 Node(10),
 Node(8),
 Node(11),
 Node(12),
 Node(13),
 Node(14)]

Que peut-on dire de ce parcours ?

Coder une telle fonction. On peut utiliser une file.

Hide code cell content
def parcours(arbre):
    file = []
    res = []
    file.append(arbre)
    while len(file) > 0:
        voisin = file.pop(0)
        res = res + [voisin]
        if voisin.left is not None:
            file.append(voisin.left)
        if voisin.right is not None:
            file.append(voisin.right)
    return res

La fonction s’utilise ainsi.

parcours(arbre2)
[Node(7),
 Node(3),
 Node(2),
 Node(6),
 Node(9),
 Node(1),
 Node(5),
 Node(10),
 Node(8),
 Node(11),
 Node(12),
 Node(13),
 Node(14)]