Aller au contenu

Arbres - Parcours

I. Retour sur les structures de donnĂ©es abstraites.⚓

Quelles techniques avons-nous pour accéder aux éléments ?

1. Pour le type abstrait liste :

Solution

Renvoyer la tĂȘte de la liste

2. Pour le type abstrait file :

Solution

DĂ©filer

3. Pour le type abstrait pile :

Solution

DĂ©piler

4. Pour le type abstrait dictionnaire :

Solution

AccÚs par clé

. Pour le type list de python :

Solution

AccÚs par index, ou par élément

II. Rappel : Les Arbre binaires⚓

Arbres binaires

  • Un arbre binaire est une structure permettant de stocker une collection de donnĂ©es de mĂȘme type.
  • Ce n'est pas une structure linĂ©aire.
  • Le principal avantage des arbres par rapport aux listes est qu’ils permettent de ranger les donnĂ©es de telle sorte que les recherches soient plus efficaces.
  • Pour accĂ©der Ă  un Ă©lĂ©ment quelconque d’un arbre , il faut "descendre" dans l’arbre jusqu’à cet Ă©lĂ©ment.

Arbre généalogique de Louis XIV

Comme nous l'avons déjà vu, certaines données ont naturellement une structure d'arbre binaire. C'est le cas d'un arbre généalogique ascendant (recherche du pÚre et de la mÚre) .

Exemple pour Louis XIV :

graph TD
D(Henri IV)
E(Maria de Medicis)
F(Felipe III d'Espagne)
G(Margareta d'Autriche)
B(Louis XIII)
C(Anna d'Autriche)
A(Louis XIV)
D --- B
E --- B
F --- C
G --- C
B --- A
C --- A

😊 De façon plus conforme Ă  la thĂ©orie des arbres, nous aurions pu reprĂ©senter cet arbre de la façon suivante, en plaçant la racine en haut :

graph TD
A(Louis XIV)
B(Louis XIII)
C(Anna d'Autriche)
D(Henri IV)
E(Maria de Medicis)
F(Felipe III d'Espagne)
G(Margareta d'Autriche)
A --- B
A --- C
B --- D
B --- E
C --- F
C --- G

Les parcours

  • Un parcours en largeur nous permettra de parcourir successivement toutes les personnes d'une mĂȘme gĂ©nĂ©ration.

  • Un parcours en profondeur nous permettra de parcourir l'arbre "par branche".

III. 🏃‍ Parcours en largeur des arbres⚓

BFS

  • Ce parcours est parfois notĂ© BFS pour Breadth-First Search
  • Le parcours en largeur correspond Ă  un parcours par niveau de noeuds de l'arbre. Un niveau est un ensemble de nƓuds ou de feuilles situĂ©s Ă  la mĂȘme profondeur.

👉 C'est un parcours Ă©tage par Ă©tage (de haut en bas) et de gauche Ă  droite.

largeur

Dans cet exemple, on obtient successivement : 3, 1, 4, 5, 2, 0.

👉 Pour Ă©tudier cet algorithme de parcours en largeur, nous allons utiliser une file.

Les files

Quel est le principe d'une file ?

Solution

En informatique, une file (queue en anglais ) est une structure de donnĂ©es basĂ©e sur le principe «Premier entrĂ©, premier sorti», en anglais FIFO (First In, First Out), ce qui veut dire que les premiers Ă©lĂ©ments ajoutĂ©s Ă  la file seront les premiers Ă  ĂȘtre rĂ©cupĂ©rĂ©s.

Le module queue de Python

Nous avons déjà vu plusieurs implémentations possibles des files, nous allons ici utiliser celle de Python : le module Queue

Extrait de la documentation en français de python sur le module Queue qui est une implémentation des files. (Documentation officielle)

Les objets Queue (Queue, LifoQueue ou PriorityQueue) fournissent les méthodes publiques décrites ci-dessous.

  • f = Queue() CrĂ©Ă© une file vide nommĂ©e f.
  • f.qsize() renvoie la taille de la file f.
  • f.empty() renvoie True si la file f est vide, False sinon
  • f.put(item) ajoute item dans la file f
  • f.get() dĂ©file (retire) et renvoie l'Ă©lĂ©ment dĂ©filĂ© de la file f.

D'aprĂšs le cours de Gilles Lassus

MĂ©thode

  • On place l'arbre dans la file.
  • Tant que la file n'est pas vide, on procĂšde comme suit :
    • On dĂ©file, donc on rĂ©cupĂšre l'arbre situĂ© en haut de la file.
    • Si cet arbre n'est pas vide :
      • On garde son Ă©tiquette.
      • On enfile son sous-arbre gauche, puis son sous-arbre droit.

arbres BFS

À vous

Ecrire les Ă©tats suivants de la file. Nous admettons ici qu'un arbre vide est None.

Solution

files arbre test

Classe Arbre simplifiĂ©e, sans encapsulation ❀

Exécuter le script suivant :

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Créer l'arbre tests

Compléter le script suivant pour créer l'arbre de la figure ci-dessus

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution
🐍 Script Python
# arbre-test
a = Arbre(8)
a.left = Arbre(4)
a.right = Arbre(5)
a.left.left = Arbre(2)
a.left.right = Arbre(1)
a.right.right = Arbre(3)
À vous

Compléter le script suivant : la fonction parcours_BFS doit renvoyer la liste des noeuds obtenue par le parcours en largeur de l'arbre.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution
🐍 Script Python
def parcours_BFS(arbre):
    file = Queue()
    file.put(arbre)
    solution = []
    while not file.empty():
        a = file.get()
        if a is not None :
            solution.append(a.data)
            file.put(a.left)
            file.put(a.right)
    return solution
Tester

Tester ci-dessous la fonction parcours_BFS pour l'arbre test créé au-dessus.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution
🐍 Script Python
print(parcours_BFS(a))

✍ A noter ... et Ă  mĂ©moriser ... 🐘

f = File() # Création d'une file vide
f.enfiler(arbre)
tant que f non vide : arbre_au_sommet = f.defiler() si arbre_au_sommet n'est pas vide On garde son Ă©tiquette f.enfiler(son sous-arbre gauche) f.enfiler(son sous-arbre droit) fin si fin tant que

IV. Les parcours en profondeur - GĂ©nĂ©ralitĂ©s⚓

Le principe

  • Dans le cas d'un parcours en profondeur, l'un des deux sous-arbres est complĂštement explorĂ© avant que l'exploration du second ne commence.

  • On distingue trois types de parcours selon l'ordre dans lequel le sous-arbre de gauche, le sous-arbre droit et la racine sont explorĂ©s.

balade et contours

Pour parcourir un arbre en profondeur, on se "balade" autour de l'arbre de la façon suivante (en commençant toujours par la gauche) :

Les flÚches numérotées en pointillé, qui sont représentées à cÎté des branches de l'arbre indiquent comment on se "balade" autour de l'arbre.

Ainsi on a les parcours successifs suivants:

  • la flĂšche 1 indique que l'on va de r Ă  a
  • la flĂšche 2 indique que l'on va de a Ă  c
  • la flĂšche 3 indique que l'on va de c Ă  h
  • la flĂšche 4 indique que l'on va de h Ă  c

etc.

👉 Nous avons donc la "balade" r, a, c, h, c, a, d, i, d, j, l, j, d, a, r, b, e, k, e, b, f, b, r , que l'on appelera le "contours";

balade 1

Source : https://math.univ-lyon1.fr/irem/IMG/pdf/parcours_arbre_avec_solutions-2.pdf

PremiÚre définition des trois parcours

On dĂ©finit trois parcours des sommets de l’arbre :

  • L’ordre prĂ©fixe : on liste chaque sommet la premiĂšre fois qu’on le rencontre dans la balade.
    Chaque nƓud est visitĂ© avant que ses deux fils le soient.
    On part de la racine, on visite le fils gauche (et Ă©ventuellement le fils gauche de celui-ci, etc.) avant de remonter et de redescendre vers le fils droit.

Cela donne ici : r, a, c, h, d, i, j, l, b, e, k, f

  • l’ordre suffixe (aussi appelĂ© postfixe en anglais) : on liste chaque sommet la derniĂšre fois qu’on le rencontre.
    Chaque nƓud est visitĂ© aprĂšs que ses deux fils le soient.
    On visite le fils gauche, puis le fils droit, puis la racine

Cela donne ici : h, c, i, l, j, d, a, k, e, f , b, r

  • l’ordre infixe (plus compliquĂ©!): chaque nƓud est visitĂ© (listĂ©) aprĂšs son fils gauche mais avant son fils droit.
    Si c'est une feuille il est donc listé (son fils gauche et son fils droit sont vides)
    On visite le fils gauche, puis la racine, puis le fils droit

Cela donne ici : c, h, a, i ,d, l, j, r, k, e, b, f

😀 Ces trois parcours sont naturellement rĂ©cursifs.

DeuxiÚme définition des trois parcours

💡 On ajoute les fils fantîmes manquants 😀

balade 2

On peut ainsi considĂ©rer qu’on passe une fois Ă  gauche de chaque nƓud (en descendant), une fois en dessous de chaque nƓud, une fois Ă  droite de chaque nƓud (en remontant).

ordres préfixe, suffixe, infixe

  • Ordre prĂ©fixe : lorsque l'on passe Ă  gauche des nƓuds.

👉 Regarder cette vidĂ©o : ordre prĂ©fixe

  • Ordre suffixe : lorsque l'on passe Ă  droite des nƓuds.

👉 Regarder cette vidĂ©o : ordre suffixe

  • Ordre infixe : lorsque l'on passe sous les noeuds

👉 Regarder cette vidĂ©o : ordre infixe

Exercice 1

exo_parcours.png

Donner le rendu de chaque parcours :

  1. Parcours en largeur
  2. Parcours préfixe
  3. Parcours infixe
  4. Parcours postfixe

largeur : 1 2 3 4 5 6 7 8 9

préfixe : 1 2 4 5 7 8 3 6 9

infixe : 4 2 7 5 8 1 3 9 6

postfixe : 4 7 8 5 2 9 6 3 1

Exercice 2

exo_2.png

Donner le rendu de chaque parcours :

  1. Parcours en largeur
  2. Parcours préfixe
  3. Parcours infixe
  4. Parcours postfixe

largeur : 9 8 7 6 2 5 1 4 3

préfixe : 9 8 6 2 1 7 5 4 3

infixe : 6 8 1 2 9 7 4 5 3

postfixe : 6 1 2 8 4 3 5 7 9

Exercice débranché : Expérimentons ces trois parcours dans le cas concret d'un labyrinthe

Voici un labyrinthe :

im lab

Les cercles vides sont des nƓuds sans intersection, les cercles pleins sont des culs de sac, les carrĂ©s sont des intersections, l'entrĂ©e et la sortie sont marquĂ©es par un cercle plein dans un cercle vide.

Ce labyrinthe est parfait : chaque cellule est reliée à toutes les autres et, ce, de maniÚre unique

Contrairement au labyrinthe Ă©tudiĂ© dans le cours sur les graphe, celui-ci peut donc ĂȘtre reprĂ©sentĂ© par un arbre (il n'y a pas de cycle)

a. Faire la représentation de ce labyrinthe avec un arbre (sur feuille).

  • Pour nommer un nƓud, il a Ă©tĂ© choisi de donner en premier le numĂ©ro de la colonne, et en deuxiĂšme le numĂ©ro de la ligne. Le nƓud d'entrĂ©e est donc le (0,4) et celui de sortie le (5,4).
  • On part du nƓud (0,4) qui sera la racine de cet arbre. Lorsqu'il n'y a qu'un fils, on convient de le placer obligatoirement Ă  gauche, et lorsqu'il y a une intersection, placez bien entendu Ă  gauche le nƓud quand on va vers la gauche et Ă  droite quand on va Ă  droite.
  • 👉 Pour simplifier, on notera 04 Ă  la place (0, 4), 14 Ă  la place de (1, 4) etc...

Dessin Ă  faire sur votre feuille

b. Quelle est la hauteur de l'arbre ?

Solution

RĂ©ponse : 12

c. Quelle est la profondeur du nƓud (5,4) ? Qu'est-ce que cette profondeur reprĂ©sente dans notre problĂšme ?

Solution

RĂ©ponse : 9

C'est la longueur du plus court chemin vers la sortie.

d. Différents parcours en profondeur de cet arbre

đŸ’đŸ»

📌Appelez votre professeur pour qu'il vous donne une version papier Ă  complĂ©ter. Vous devez rĂ©aliser les trois parcours en profondeur vus (prĂ©fixe, suffixe et infixe) sur cet arbre.

Pour une question de mise en page quand il n'y a qu'un seul fils la flÚche est dessinée verticale (et non vers la gauche)

Vous pouvez aussi tĂ©lĂ©charger ce document ici : 🌐 Arbres Ă  complĂ©ter

Correction du parcours préfixe

préfixe

Correction du parcours suffixe

suffixe

Correction du parcours infixe

infixe

📌Quel est le parcours qui donne le chemin le plus court pour trouver la sortie?

Solution

RĂ©ponse : parcours suffixe

📌Aurions-nous pu trouver un chemin plus rapide?

Solution

RĂ©ponse : il suffit de faire (0,4), (1,4), (2,4), (3,4), (4,4), (4,3), (4,2), (5,2), (5,3), (5,4)

Remarque

đŸŒ” La structure d'arbre n'est pas adaptĂ©e Ă  la recherche de chemins, ou du plus court chemin. Nous verrons plus tard comment rĂ©soudre ce problĂšme avec des parcours de graphe.

V. ImplĂ©mentation des parcours en profondeur⚓

Une classe Arbre

Il faut absolument exécuter ce code pour pouvoir travailler ensuite.

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

1. Le parcours prĂ©fixe⚓

On donne le pseudo-code suivant :

fonction parcours_prefixe(arbre) :
    si arbre is not None :
        affiche arbre.valeur
        parcours_prefixe(arbre.gauche)
        parcours_prefixe(arbre.droit)
A vous de jouer 1

Compléter le code suivant, et le tester pour arbre1 (arbre ci-dessous)
Vérifier à la main que le résultat est bien correct.

flowchart TD
    a(A)
    b(B)
    c(C)
    d(D)
    e(E)
    f(F)
    g( )
    h( )
    i(G)
    a --- b
    a --- c
    b --- d
    b --- e
    c --- f
    c --- g
    d --- h
    d --- i
    linkStyle 5 stroke-width:0px;
    linkStyle 6 stroke-width:0px;
    style g opacity:0;
    style h opacity:0;

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution
🐍 Script Python
# version simple avec print (renvoie None)
def parcours_prefixe(arbre) :
    if arbre is not None :
        print(arbre.valeur)
        parcours_prefixe(arbre.gauche)
        parcours_prefixe(arbre.droit)

# création de l'arbre :
arbre1 = Arbre("A")
arbre1.ajout_gauche("B")
arbre1.ajout_droit("C")
arbre1.gauche.ajout_gauche("D")
arbre1.gauche.ajout_droit("E")
arbre1.gauche.gauche.ajout_droit("G")
arbre1.droit.ajout_gauche("F")

# parcours
parcours_prefixe(arbre1)    
A vous de jouer 2

Au lieu de simplement afficher les nƓuds visitĂ©s, nous allons en constituer la liste.

Compléter :

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier
Évaluations restantes : 5/5

.128013ldy14]k/weibmc_:3aPr+ =o[f.gt2sSh)(pNunxv050c0k0D0s0l0b0F0w0o0b0s0F0F0x010D0l0K010406050F0M0n0n0s0u0d040G0y0b0M0*0y0N050i0;0?0^0`0/0K04051a131d0i1a0/0c0l0P0Y0!0$0(0H0l0C0H0b1r0H0D0-050T0m0b0k1m0#0%011q1s1u1s0D1A1C1y0D0u1b0D0H0Y0}0F0K0s0N0(0E011E1o010A0V0k0N0s0n0k1y1X1Z1(1G1+1C1.1:0-0a0w0t0u0y0K0y0F0l100N0w0R1V0u0u0k0o28131?0N1b0i1T2l1Q1S1R1z0c1^0(1u0N1-251y1j1l0Z1F2v0l2x0N0y2B1y0K2e1b2j2l2P0:1Y292D1)2I0u0@0b0-0e2i2T0.2S1@2V1G2X2Z0-0E2%1Z2)2j2u012.0s2!040r2=2k0/2^2,0(2{2}0f302l2M0k2l2B2o0c1S2t34010o2J1;1b3e1c2N2*2k39053l0R2O2T2_0h0-0R0A390w3s2_0N0A0-1Y0u3l0M0u0F0p3b1+0O0k0p1u0F0D0k3u331n1G0,040J3$3z3j0N0-0^0m2e3-2+3(0(3*0I0q39060w413G3%2E013B040l3E142(433.3`2`3;0u3?3#4b2?4d3_450y0j0-0l0F3F3H3j0h0o0-0L114k2P4n2U4f3*3~4l2k0w40424O4w4f472e0D3P124K044F2_3*0z0g3 4P441)4S0S4V4v4*3)0-0z3^4G453:043=3@4X4Q4p0-0B4@3I0-0P2|0k3P533j3*4%4X4Z3j0y0-0v4/4e4_3L0^3O3Q3S2e3U3W3Y3!5a4H0-3,4~4:354h4j5x5004525B5l2W0-0C0s0M0o0H4D2(4 1)3|5k4o1)5h045j5e5V2-5n3N0y3P3R3T0l3V3X4t5w5K5Z4;3+5G5M4{4i4}2R5C015#5J625L5*040c22275}5{0I3 133w3c1e3r0i3p2m3g132p6r0s1B6k6n1k2)6n0S0U0W04.

Retenir

préfixe : RGD (racine, sous-arbre gauche, sous-arbre droit)

Racine en 1er

Parcours préfixe

fonction parcours_prefixe(arbre):
    si arbre is not None :
        affiche arbre.valeur
        parcours_prefixe(arbre.gauche)
        parcours_prefixe(arbre.droit)

👉 ou si on doit renvoyer une liste :

fonction parcours_prefixe(arbre):
    si arbre is None :
        renvoyer une liste vide
    sinon :
        renvoyer [arbre.valeur] + parcours_prefixe(arbre.gauche) + parcours_prefixe(arbre.droit)

2. Le parcours suffixe⚓

On donne le pseudo-code suivant :

fonction parcours_suffixe(arbre) :
    si arbre is not None :
        parcours_suffixe(arbre.gauche)
        parcours_suffixe(arbre.droit)
        affiche arbre.valeur
A vous de jouer 3

Compléter le code suivant, et le tester pour arbre1 (arbre ci-dessous)
Vérifier à la main que le résultat est bien correct.

flowchart TD
    a(A)
    b(B)
    c(C)
    d(D)
    e(E)
    f(F)
    g( )
    h( )
    i(G)
    a --- b
    a --- c
    b --- d
    b --- e
    c --- f
    c --- g
    d --- h
    d --- i
    linkStyle 5 stroke-width:0px;
    linkStyle 6 stroke-width:0px;
    style g opacity:0;
    style h opacity:0;

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution
🐍 Script Python
def parcours_suffixe(arbre):
    if arbre is not None:
        parcours_suffixe(arbre.gauche)
        parcours_suffixe(arbre.droit)
        print(arbre.valeur) 
A vous de jouer 4

Au lieu de simplement afficher les nƓuds visitĂ©s, nous allons en constituer la liste.

Compléter :

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier
Évaluations restantes : 5/5

.128013ldy14]k/eibmc_:3aPr+ =o[f.gt2sSh)(pNunxv050c0j0C0r0k0b0E0v0n0b0r0E0E0w010C0k0J010406050E0L0m0m0r0t0d040F0x0b0L0)0x0M050i0:0=0@0_0.0J040519121c0i190.0c0k0O0X0Z0#0%0G0k0B0G0b1q0G0C0,050S0l0b0j1l0!0$011p1r1t1r0C1z1B1x0C0t1a0C0G0X0|0E0J0r0M0%0D011D1n010z0U0j0M0r0m0j1x1W1Y1%1F1*1B1-1/0,0a0v0s0t0x0J0x0E0k0 0M0v0Q1U0t0t0j0n27121=0M1a0i1S2k1P1R1Q1y0c1@0%1t0M1,241x1i1k0Y1E2u0k2w0M0x2A1x0J2d1a2i2k2O0/1X282C1(2H0t0?0b0,0e2h2S0-2R1?2U1F2W2Y0,0D2$1Y2(2i2t012-0r2Z040q2;2j0.2@2+0%2`2|0f2 2k2L0j2k2A2n0c1R2s33010n2I1:1a3d1b2M2)2j38053k0Q2N2S2^0h0,0Q0z380v3r2^0M0z0,1X0t3k0L0t0E0o0:0z1*0N0j0o1t0E0C0j3t321m1F0+040I3$3y3i0M0,0@0l2d3-2*3(0%3*0H0p38060v413F3%2D013A040k3D132%433.3`2_3;0t3?3#4b2=4d3_450x0,0w0w3E3G3i0h0n0,0K104k2O4n2T4f3*3~4l2j0v40424N4v4f472d0C3O114J044E2^3*0y0g3 4O441(4R0R4U4u4)2,3K0@3N3P3R0L3T0k3V3X0k3Z4C2%4P453*3,4W522V4h4j3^4F4p0,0A5b3H0,0B0r0L0n0G502=573)0,0H4.4e5d040u5u4o58043L4?3Q3S3U3W3Y3!5g3i545L4f3:043=3@564/0%4q045f5U5v5B0c21265O535s5z5c1(5X5y4W4Y5M0,0y5*5B5S5o3s5V015X5Z2Q5 5Q0O2{0j3O5`5r044$4W0.0i3v3b1d3q0i3o2l3f122o6p0r1A6i6l1j2(6l0R0T0V04.

Retenir

suffixe : GDR (sous-arbre gauche, sous-arbre droit, racine)

Racine en dernier

Parcours suffixe

fonction parcours_suffixe(arbre) :
    si arbre is not None :
        parcours_suffixe(arbre.gauche)
        parcours_suffixe(arbre.droit)
        affiche arbre.valeur

👉 ou si on doit renvoyer une liste :

fonction parcours_suffixe(arbre) :
    si arbre is None :
        renvoyer une liste vide
    sinon :
        renvoyer parcours_suffixe(arbre.gauche) + parcours_suffixe(arbre.droit) + [arbre.valeur] 

3. Le parcours infixe⚓

On donne le pseudo-code suivant :

fonction parcours_infixe(arbre) :
    si arbre is not None :
        parcours_infixe(arbre.gauche)
        affiche arbre.valeur
        parcours_infixe(arbre.droit)
A vous de jouer 5

Compléter le code suivant, et le tester pour arbre1 (arbre ci-dessous)
Vérifier à la main que le résultat est bien correct.

flowchart TD
    a(A)
    b(B)
    c(C)
    d(D)
    e(E)
    f(F)
    g( )
    h( )
    i(G)
    a --- b
    a --- c
    b --- d
    b --- e
    c --- f
    c --- g
    d --- h
    d --- i
    linkStyle 5 stroke-width:0px;
    linkStyle 6 stroke-width:0px;
    style g opacity:0;
    style h opacity:0;

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution
🐍 Script Python
def parcours_infixe(arbre):
    if arbre is not None:
        parcours_infixe(arbre.gauche)
        print(arbre.valeur)
        parcours_infixe(arbre.droit)
A vous de jouer 6

Au lieu de simplement afficher les nƓuds visitĂ©s, nous allons en constituer la liste.

Compléter :

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier
Évaluations restantes : 5/5

.128013ldy14]k/weibmc_:3aPr+ =o[f.gt2sSh)(pNunxv050c0k0D0s0l0b0F0w0o0b0s0F0F0x010D0l0K010406050F0M0n0n0s0u0d040G0y0b0M0*0y0N050i0;0?0^0`0/0K04051a131d0i1a0/0c0l0P0Y0!0$0(0H0l0C0H0b1r0H0D0-050T0m0b0k1m0#0%011q1s1u1s0D1A1C1y0D0u1b0D0H0Y0}0F0K0s0N0(0E011E1o010A0V0k0N0s0n0k1y1X1Z1(1G1+1C1.1:0-0a0w0t0u0y0K0y0F0l100N0w0R1V0u0u0k0o28131?0N1b0i1T2l1Q1S1R1z0c1^0(1u0N1-251y1j1l0Z1F2v0l2x0N0y2B1y0K2e1b2j2l2P0:1Y292D1)2I0u0@0b0-0e2i2T0.2S1@2V1G2X2Z0-0E2%1Z2)2j2u012.0s2!040r2=2k0/2^2,0(2{2}0f302l2M0k2l2B2o0c1S2t34010o2J1;1b3e1c2N2*2k39053l0R2O2T2_0h0-0R0A390w3s2_0N0A0-1Y0u3l0M0u0F0p2G1+0O0k0p1u0F0D0k3u331n1G0,040J3$3z3j0N0-0^0m2e3-2+3(0(3*0I0q39060w413G3%2E013B040l3E142(433.3`2`3;0u3?3#4b2?4d3_450y0j0-0l0F3F3H3j0h0o0-0L114k2P4n2U4f3*3~4l2k0w40424O4w4f472e0D3P124K044F2_3*0z0g3 4P441)4S0S4V4v4*2-3L0^3O3Q3S3J0l3V3X4t3!3^4G453*3,4X4Q453:043=3@554:0(0y0-0B503I0-0C0s0M0o0H4D2(561)3|4/4e4p0-0v5v4o5t0-0z5i3/4h4j5F4f5f045h5c5w2W0-0P2|0k3P5J520-4%4X4Z3j5L5z5!5s4;043M4@3R3T4{3W3Y4 5O5B3)0-542R5d4g594i5b5}5P1G5L5N635_353C22275W5C040I3 133w3c1e3r0i3p2m3g132p6s0s1B6l6o1k2)6o0S0U0W04.

Retenir

infixe : GRD (sous-arbre gauche, racine, sous-arbre droit)

Racine au milieu

Parcours infixe

fonction parcours_infixe(arbre) :
    si arbre is not None :
        parcours_infixe(arbre.gauche)
        affiche arbre.valeur
        parcours_infixe(arbre.droit)

👉 ou si on doit renvoyer une liste :

fonction parcours_infixe(arbre) :
    si arbre is None :
        renvoyer une liste vide
    sinon :
        renvoyer parcours_infixe(arbre.gauche) + [arbre.valeur]  + parcours_infixe(arbre.droit) 

4. Quel parcours choisir ?⚓

Retenir

Nous avons vu que le parcours en largeur Ă©tait pertinent pour avoir des renseignements plutĂŽt par niveau, utile par exemple si on veut connaĂźtre les personnes d'une mĂȘme gĂ©nĂ©ration.

Le parcours préfixe, parcourt l'arbre en profondeur plutÎt de maniÚre descendante, et le suffixe plutÎt de maniÚre ascendante.

Quel est l'intĂ©rĂȘt du parcours infixe ?
Nous allons voir cela dans le paragraphe suivant. 😀

5. Parcours infixe sur un arbre binaire de recherche.⚓

Exemple

Le tri du bijoutier (d'aprĂšs un sujet de l'APMEP)

ConsidĂ©rons le problĂšme du bijoutier voulant trier par grosseur un tas de diamants : pour faire cette opĂ©ration il se sert d’un tamis ce qui lui permet de sĂ©parer le tas initial en deux, et il recommence avec de nouveaux tamis pour chaque tas. On le comprend facilement l’efficacitĂ© du tri est fonction des trames des tamis utilisĂ©s.
Nous allons utiliser une idée similaire pour créer un arbre binaire, et pour construire les algorithmes permettant de le parcourir.
Mieux qu’un grand discours montrons la construction de l’arbre correspondant aux donnĂ©es 7, 3, 1, 8, 6.
Nous allons placer le premier élément 7 à la racine d'un arbre.
Principe du tamis : pour n'importe quel noeud, tous les noeuds se trouvant dans son sous-arbre gauche ont une valeur inférieure, et tous ceux se trouvant dans le sous arbre droit ont une valeur supérieure. Le sous arbre gauche correspond à ce qui est passé dans les trous du tamis, et le sous-arbre droit à ce qui est resté dans le tamis.
- 3 < 7 donc 3 est fils gauche de 7
- 1 < 3 donc 1 est fils gauche de 3
- 8 > 7 donc 8 est fils droit de 7. (on ne peut pas mettre 8 comme fils droit de 3, car sinon 8 serait dans le sous-arbre gauche de 7, ce qui est impossible car ce sous-arbre ne doit contenir que des nombres inférieurs à 7).
- 6 > 3 et 6 < 7 donc 6 est fils droit de 3.

On obtient l'arbre suivant :

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Nous venons de créer un arbre binaire de recherche

Nous reviendrons plus tard en détail sur cette structure de données.

A vous de jouer 7

Reprenons cet exemple et implémentons le avec la classe Arbre du début.

Compléter ci-dessous. Que constatez-vous ?

###(DĂ©s-)Active le code aprĂšs la ligne # Tests (insensible Ă  la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Ctrl+Clic pour inverser les colonnes)
Entrer ou sortir du mode "plein Ă©cran"
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activĂ©, le texte copiĂ© dans le terminal est joint sur une seule ligne avant d'ĂȘtre copiĂ© dans le presse-papier

Solution

🐍 Script Python
# Compléter ci-dessous
abr = Arbre(7)
abr.ajout_gauche(3)
abr.gauche.ajout_gauche(1)
abr.gauche.ajout_droit(6)
abr.ajout_droit(8)  
On constate que l'on obtient les noeuds triés par ordre croissant.

😃

🐘 A retenir

Le parcours infixe sur un arbre binaire de recherche trie les noeuds de cet arbre.

👉 C'est un des trĂšs grands intĂ©rĂȘts des arbres binaires de recherche, et du parcours infixe.

VI. TP final⚓

⌛ Avant de commencer

Vous devez travailler sur Basthon

TĂ©lĂ©charger dans le mĂȘme dossier :

😀 La correction est arrivĂ©e ...

TĂ©lĂ©charger dans le mĂȘme dossier :

VII. ✍ Bilan⚓

Parcours en largeur

aVoir <- fileVide
enfiler la racine
vus = listeVide (si on doit renvoyer le parcours)
tant que aVoir non vide :
    a <- defiler()
    visiter a (ajout dans une liste vus, ou affichage)
    si a.filsG not None: 
        enfiler a.filsG
    si a.filsD not None: 
        enfiler a.filsD

Parcours préfixe

def prefixe(arbre) :
    if arbre is None :
        return []
  else :
        return [arbre.valeur] + prefixe(arbre.filsG) +  prefixe(arbre.filsD) 

Parcours suffixe

def suffixe(arbre) :
    if arbre is None :
        return []
    else :
        return  suffixe(arbre.filsG)  + suffixe(arbre.filsD) + [arbre.valeur]

Parcours infixe

def infixe(arbre) :
  if arbre is None :
      return []
  else :
      return  infixe(arbre.filsG) + [arbre.valeur] + infixe(arbre.filsD)

VIII. VidĂ©os pour approfondir⚓

Parcours préfixe

Parcours suffixe

😉 Le parcours suffixe se fait de façon analogue.

Parcours infixe

🌳 CrĂ©dits⚓

Jean-Louis Thirot , Mireille Coilhac, Valérie Mousseaux, Gilles Lassus