Arbres - Généralités
I. Introduction⚓︎
Source Gilles Lassus
Arbre
Un arbre est une structure hiérarchique permettant de représenter de manière symbolique des informations structurées.
L'arborescence d'un disque dur
Les systèmes Unix (MacOS ou GNU/Linux) organisent leur disque dur suivant l'arborescence ci-dessous :
Un arbre généalogique des descendants ou des ascendants
graph TD
A(Vous)
B(Père)
C(Mère)
F(Grand-père paternel)
G(Grand-mère paternelle)
D(Grand-père maternel)
E(Grand-mère maternelle)
A --- B
A --- C
B --- F
B --- G
C --- D
C --- E
Organisation des matchs d'un tournoi de sport
graph TD
A(Vainqueur)
B(Finaliste 1)
C(Finaliste 2)
D(Demi-finaliste 1)
E(Demi-finaliste 2)
F(Demi-finaliste 3)
G(Demi-finaliste 4)
H(Quart-finaliste 1)
I(Quart-finaliste 2)
J(Quart-finaliste 3)
K(Quart-finaliste 4)
L(Quart-finaliste 5)
M(Quart-finaliste 6)
N(Quart-finaliste 7)
P(Quart-finaliste 8)
A --- B
A --- C
B --- D
B --- E
C --- F
C --- G
D --- H
D --- I
E --- J
E --- K
F --- L
F --- M
G --- N
G --- P
II. Terminologie⚓︎
Attention
l'analogie avec les arbres réels peut s'avérer trompeuse. Les arbres - en informatique - sont le plus souvent représentés avec la racine en haut, puis les nœuds, et les feuilles en bas.
Un arbre
Un arbre est une structure hiérarchique de données, composée de nœuds.
Source Gilles Lassus
-
Chaque nœud a exactement un seul nœud père, à l'exception du nœud racine qui est le seul nœud à ne pas avoir de père. (oui, la racine d'une arbre est en haut)
-
Chaque nœud peut avoir un nombre quelconque de fils, dont il est le père.
- Les nœuds qui n'ont pas de fils sont appelés les feuilles (ou nœuds externes).
- Les nœuds qui ne sont pas des feuilles sont des nœuds internes.
- Le nom de chaque nœud est appelé son étiquette.
Exemple
graph TD
A(A)
B(B)
C(C)
D(D)
E(E)
F(F)
G(G)
H(H)
I(I)
A --- B
A --- C
B --- D
B --- E
B --- F
C --- G
E --- H
E --- I
- La racine est le nœud A.
- Le nœud B possède 3 fils (les nœuds D, E et F), le noeud C possède un fils (le nœud G), le nœud F ne possède aucun fils.
- Le nœud B a pour père le nœud A.
- Les feuilles sont les nœuds D, H, I, F et G (ceux qui n'ont pas de fils).
Attention
Attention : il faut bien repérer dans les définitions suivantes, si on compte les nœuds, ou si on regarde la longueur d'une branche.
Il y a en effet un décalage de 1 entre ces deux nombres.
Conventions retenues dans ce cours
- ⚠️Un arbre ne contenant qu'un élément à une hauteur de 1.
- La profondeur de la racine est 0
Définitions
-
La taille d'un arbre est le nombre de nœuds qu'il possède.
-
La profondeur d'un nœud ou d'une feuille d'un arbre est la longueur du chemin le plus court vers la racine .
- La profondeur d’un nœud est égale à la profondeur de son père plus 1
- Si un nœud est à une profondeur \(p\), tous ses fils sont à une profondeur \(p+1\)
-
Il existe plusieurs méthode pour déterminer la profondeur d'un nœud :
- La profondeur d'un nœud est le nombre d'arêtes entre la racine et ce nœud (c'est la convention retenue dans ce cours)
- La profondeur d’un nœud est le nombre de nœuds du chemin qui va de la racine à ce nœud sans compter la racine
-
🤿 on peut imaginer que la racine est à la surface de l'eau, donc à une profondeur 0, et que les nœuds sont à des profondeurs 1, 2, 3, etc.
Dans l'arbre précédent :- profondeur de B = 1
- profondeur de I = 3 .
-
La hauteur d’un arbre est le nombre de nœuds du plus long chemin de la racine aux feuilles en comptant la racine et la feuille.
Dans l'arbre précédent : hauteur de l'arbre = 4
Autres définitions
Attention : On trouve aussi dans la littérature, que la profondeur de la racine est égale à 1, ce qui modifie la hauteur de l'arbre également puisqu'alors l'arbre réduit à la racine a pour hauteur 0 et l'arbre vide a pour hauteur -1. Les deux définitions se valent, il faut donc bien lire celle qui est donnée.
Exemple
graph TD
A(A)
B(B)
C(C)
D(D)
E(E)
F(F)
G(G)
H(H)
I(I)
A --- B
A --- C
B --- D
B --- E
B --- F
C --- G
E --- H
E --- I
- La taille de l'arbre est égale à 9 (il possède 9 nœuds : 4 nœuds internes et 5 feuilles).
- Le nœud E a une profondeur égale à 2 (le chemin A-B-E est de longueur 2).
- La hauteur de l'arbre est égale à 4 car la branche A-B-E-H possède 4 nœuds (la profondeur maximale est égale à 3, c'est celle des nœuds les plus profonds : H et I. On a bien profondeur + 1 = hauteur).
III. Arbres binaires⚓︎
👉 Dans la suite, on ne s'intéressera qu'aux arbres dont les nœuds ont au plus deux fils.
Les arbres binaires sont des cas particuliers d'arbre : l'arbre du tournoi sportif et l'arbre "père, mère..." sont des arbres binaires, en revanche, l'arbre représentant la structure du système de fichier n'est pas un arbre binaire.
Arbre binaire
Un arbre binaire est un arbre dont tous les nœuds ont au plus deux fils.
Exemple
L'arbre vu dans le paragraphe précédent n'est pas binaire car le nœud B possède 3 fils. En revanche, l'arbre ci-dessous est lui un arbre binaire.
graph TD
A(A)
B(B)
C(C)
D(D)
F(F)
M( )
G(G)
E(E)
H(H)
I(I)
L( )
J(J)
K(K)
A --- B
A --- C
B --- D
B --- F
C --- M
C --- G
D --- E
D --- H
F --- I
F --- L
G --- J
G --- K
linkStyle 4 stroke-width:0px;
linkStyle 9 stroke-width:0px;
style L opacity:0;
style M opacity:0;
Définition et vocabulaire spécifique aux arbres binaire (A connaître par ❤️)
Les définitions vues précédemment pour des arbres quelconques restent valables pour les arbres binaires. Pour les arbres binaires :
- chaque nœud possède deux sous-arbres, éventuellement vides, que l'on appelle sous-arbre gauche et sous-arbre droit.
- les nœuds qui ne sont pas des feuilles peuvent avoir une fils gauche et/ou un fils droit.
Les sous-arbres gauche et droit de A sont eux-mêmes des arbres dont les racines sont respectivement B et C. B et C possèdent eux-même des sous-arbres gauche et droit.
- le nœud C possède un sous-arbre gauche, qui est vide, et un sous-arbre droit qui est l'arbre dont la racine est G,
- le nœud B possède un sous-arbre gauche, qui est l'arbre dont la racine est D, et un sous-arbre droit qui est l'arbre dont la racine est F.
- et ainsi de suite.
Fils gauche et fils droit
Il ne faut pas confondre fils gauche et fils droit, ainsi les arbres suivants ne sont pas les mêmes :
Structure récursive
Il est aussi important de bien noter que l'on peut aussi voir les arbres comme des structures récursives : les fils d'un nœud sont des arbres (sous-arbre gauche et un sous-arbre droite dans le cas d'un arbre binaire), ces arbres sont eux mêmes constitués d'arbres...
A vos crayons 😊
Tracez tous les arbres binaires possibles avec 3 nœuds puis quelques-uns avec 4 nœuds.
IV. Visualiser un arbre binaire⚓︎
La bibliothèque binarytree
Par curiosité, vous pouvez exécuter les lignes suivantes :
La documentation est très détaillée.
Ne vous inquiétez pas, grâce aux exemples, vous comprendrez très vite comment utiliser ce module.
Un premier exemple
Exécuter :
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
À vous de jouer : créer un autre arbre
Nous allons créer un arbre particulier : La racine est 20.
Ensuite, nous allons ajouter les noeuds suivants 5, 25, 3, 12, 21, 8, 28, 13, 6 en respectant une certaine règle :
On part de la racine. Si le noeud est plus petit, on le met à gauche, sinon à droite.
- 5 est donc à gauche de 20
- 25 est à droite de 20
- 3 est à gauche de 20, à gauche de 5
- 12 est à gauche de 20, à droite de 5
- 21 est à droite de 20, à gauche de 25
Ainsi de suite...
Voici le début de l'arbre que l'on doit obtenir
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Compléter ci-dessous pour obtenir l'arbre complété : avec les nœuds suivants 5, 25, 3, 12, 21, 8, 28, 13, 6
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Solution
from binarytree import Node
# Créer un arbre
arbre = Node(20)
arbre.left = Node(5)
arbre.right = Node(25)
arbre.left.left = Node(3)
arbre.left.right = Node(12)
arbre.right.left = Node(21)
arbre.left.right.left = Node(8)
arbre.right.right = Node(28)
arbre.left.right.right = Node(13)
arbre.left.right.left.left = Node(6)
print(arbre)
Résumé
Nous venons de créer un arbre binaire de recherche souvent noté ABR.
Nous reviendrons plus tard dans le cours sur l'étude des ABR
V. Taille d'un arbre binaire en fonction de sa hauteur.⚓︎
Les arbres binaires de hauteur 4
Les deux arbres binaires suivants sont de hauteur 4.
Nous prenons ici comme convention que la hauteur d'un arbre réduit à sa racine est 1.
À gauche, nous avons un arbre filiforme, et à droite un arbre complet.
Parmi tous les arbres binaires de hauteur 4,
celui de gauche est un exemple qui a le moins de nœuds possibles, et celui de droite un exemple où il y a le plus de nœuds possibles.
Nombre de nœuds de l'arbre 1 : 4
Nombre de nœuds de l'arbre 2 : 15
On peut remarquer que \(15=2^4 - 1\)
Les arbres binaires de hauteur 5
En procédant comme ci-dessus, on comprend aisément que le nombre minimal de nœuds pour un arbre de hauteur 5 est 5.
Le nombre maximal de nœuds est obtenu pour un arbre binaire complet :
Il y a \(1+2+4+8+16 = 31\) nœuds
On peut remarquer que \(31=2^5 - 1\)
Les arbres binaires de hauteur h
Soit \(N\) la taille d'un arbre binaire (c'est à dire son nombre de nœuds) de hauteur \(h\).
On peut démontrer que : \(\boxed{ h \leq N \leq 2^{h}-1}\)
😉 Pour les curieux : démonstration de \(N \leq 2^{h}-1\)
A chaque fois que l'on ajoute un niveau, le nombre de nœuds sur ce nouveau niveau est multiplié par 2.
(Voir le schéma pour l'arbre de hauteur 5).
Le nombre de nœuds d'un arbre binaire complet
- de hauteur 4 est donc : \(1+2+2^{2}+2^{3}\)
- de hauteur 5 est donc : \(1+2+2^{2}+2^{3}+2^{4}\)
- de hauteur \(h\) est donc : \(1+2+2^{2}+...+2^{h-1}\)
Première méthode en passant par le binaire
Le nombre \(1+2+2^{2}+...+2^{h-1}\) s'écrit en binaire : \(111...1\) avec \(h\) termes 1.
Si on ajoute 1 à ce nombre, on obtient \(100...0\) (1 suivi de \(h\) fois \(0\)) qui est égal à \(2^{h}\)
Cela prouve que \(1+2+2^{2}+...+2^{h-1}=2^{h}-1\)
Deuxième méthode en passant par le calcul algébrique
Notons \(S=1+2+2^{2}+...+2^{h-1}\). Une petite astuce est de calculer en développant \((2-1)S\).
On obtient \((2-1)S = 2+2^{2}+...+2^{h-1}+2^{h}-(1+2+2^{2}+...+2^{h-1} )\)
Après simplification, on obtient donc :
\(S=2^{h}-1\)
Troisième méthode en utilisant le cours de maths sur les suites géométriques
Si vous avez suivi la spécialité mathématiques en première, vous allez ici en trouver une application.
Notons \(S=1+2+2^{2}+...+2^{h-1}\).
On reconnait la somme des \(h\) premiers termes d'une suite géométrique de raison \(q=2\) et de premier terme \(u_{0}=1\). (Terme général : \(u_{n}=2^n)\)
La formule est donc :
\(S =\text{premier terme} \times \dfrac{1-q^{\text{nombre de termes}}}{1-q}=\text{premier terme} \times \dfrac{q^{\text{nombre de termes}}-1}{q-1}\)
\(S =1 \times \dfrac{2^h-1}{2-1}\)
Après simplification, on obtient donc :
\(S=2^{h}-1\)
👉 A retenir
\(\boxed{ h \leq N \leq 2^{h}-1}\)
Attention
⚠️ Remarque, on trouve parfois une autre convention pour la hauteur : La hauteur d'un arbre réduit à sa racine est : 0
Avec cette définition, on a :
\(\boxed{ h+1 \leq N \leq 2^{h+1}-1}\)
VI. Taille d'un arbre binaire en fonction de sa hauteur.⚓︎
taille d'un arbre de hauteur 6
-
Comme nous l'avons vu au I. la hauteur d'un arbre de \(N\) noeuds est maximale lorsque cet arbre est filiforme. Dans ce cas-là, \(N=h\). D'une manière générale, on a donc : \(h \leq N\).
-
Pour obtenir avec \(N\) noeuds un arbre de hauteur la plus petite possible, il faut au contraire qu'il soit le plus équilibré possible.
Nombre de noeuds | hauteur |
---|---|
1 | 1 |
2 ou 3 | 2 |
4 ou 5 ... ou 7 | 3 |
8 ou 9 ... ou 15 | 4 |
16 ou 17 ... ou 31 | 5 |
32 ou 33 ... ou 63 | 6 |
Utilisons le binaire
Nous pouvons écrire ce tableau en codant le nombre de noeuds en binaire. Nous obtenons :
Nombre de noeuds | hauteur |
---|---|
1 | 1 |
10 ou 11 | 2 |
100 ou 101 ... ou 111 | 3 |
1000 ou 1001 ... ou 1111 | 4 |
10000 ou 10001 ... ou 11111 | 5 |
100000 ou 100001 ... ou 111111 | 6 |
😊 Nous observons que la hauteur est exactement le nombre de bits nécessaires pour écrire le nombre de noeuds en binaire ...
Pour coder un entier en binaire, on peut procéder par divisions successives par deux, jusqu'à obtenir le quotient égal à \(0\). Il suffit ensuite de lire les restes en partant du bas, comme indiqué sur cette figure.
Notre problème se résume donc à connaître le nombre de divisions nécessaires...
🖐️ Pour 23 noeuds, on peut résoudre ce problème "à la main", en posant les divisions comme ci-dessus. 23 s'écrit en binaire sur 5 bits, il a fallu 5 divisions, la hauteur minimale est donc 5.
👉 A retenir
\(\boxed{ \text{la hauteur est exactement le nombre de bits nécessaires pour écrire le nombre de noeuds en binaire}}\)
Hauteur minimale de manière itérative
Compléter ci-dessous la fonction qui détermine la hauteur minimale de manière itérative.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Hauteur minimale de manière récursive
Compléter ci-dessous la fonction qui détermine la hauteur minimale de manière récursive.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
😉 On peut aussi faire des maths...
Le même tableau écrit avec les puissances de 2 donne :
Nombre de noeuds | hauteur minimale |
---|---|
\(2^{0 }\) | \(0+ 1=1\) |
\(2^{1 }\) ou ... \(2^{2 }-1\) | \(1+1=2\) |
\(2^{2 }\) ou ... \(2^{3 }-1\) | \(2+1=3\) |
\(2^{3 }\) ou ... \(2^{4 }-1\) | \(3+1= 4\) |
\(2^{4 }\) ou ... \(2^{5 }-1\) | \(4+1= 5\) |
\(2^{^5 }\) ou ... \(2^{6 }-1\) | \(5+1=6\) |
On constate que pour trouver la hauteur, il faut "récupérer" la puissance, et y ajouter 1.
Par définition, \(\log_{2}(2^{n})=n\)
Ainsi, \(\log_{2}(2^{2})=2\), \(\log_{2}(2^{3})=3\), \(\log_{2}(2^{0})=0\) etc...
Autre exemple : \(\log_{2}(13)\approx 3,7\). Or la hauteur correspondant pour \(13\) noeuds est \(3+1=4\) (voir le schéma).
Pour un nombre \(N\) de noeuds, la hauteur est au moins égale à la partie entière de \(\log_{2}(N)\) à laquelle on ajoute 1, c'est à dire à l'arrondi à l'unité inférieure de \(\log_{2}(N)\), à laquelle on ajoute 1.
On note \(\left\lfloor \log_{2}(N)\right\rfloor+1\).
Les symboles \(\left\lfloor \quad \right\rfloor\) signifient "partie entière".
👉 A retenir
\(\boxed{ \left\lfloor \log_{2}(N)\right\rfloor+1 \leq h \leq N}\)
Attention
⚠️ Remarque, on trouve parfois une autre convention pour la hauteur : La hauteur d'un arbre réduit à sa racine est : \(0\).
Avec cette définition, on a :
\(\boxed{ \left\lfloor \log_{2}(N)\right\rfloor \leq h \leq N -1}\)
🤔 Comment obtenir \(\log_{2}(N)\) avec la calculatrice ?
Deux méthodes permettent de déterminer \(\log_{2}(13)\) par exemple :
- En utilisant la touche ln: taper successivement ln 13 \(\div\) ln 2
- En utilisant la touche log : taper successivement log 13 \(\div\) log 2
🤔 Comment obtenir \(\log_{2}(N)\) en Python ?
Tester ci-dessous
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
Hauteur minimale en utilisant le logarithme
Compléter ci-dessous la fonction qui détermine la hauteur minimale, en utilisant le \(\log_{2}\)
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)
VII. Implémentations⚓︎
Plusieurs possibilités
Il existe, comme toujours, plusieurs implémentations possibles d'un arbre binaire. Nous allons voir dans ce TP quelques possibilités qui s'offrent à nous.
Partie 1 : implémentation avec une seule classe
Télécharger les trois fichiers, et les enregistrer dans un même dossier.
Attention
Si les téléchargements ne fonctionnent pas, utiliser le navigateur Firefox.
🌐 Fichier à télécharger : Fichier visu_arbre_3.py
: "Clic droit", puis "Enregistrer la cible du lien sous"
🌐 Fichier à télécharger : Fichier visu_tree.py
: "Clic droit", puis "Enregistrer la cible du lien sous"
🌐 Notebook jupyter à télécharger : Fichier arbres_une_classe_sujet.ipynb
: "Clic droit", puis "Enregistrer la cible du lien sous"
Lien pour lire le notebook jupyter : Notebook Basthon
⏳ La correction viendra bientôt ...
Partie 2 : implémentation avec un dictionnaire
Après avoir téléchargé le fichier, vous pourrez le lire à partir de Basthon
Attention
Si les téléchargements ne fonctionnent pas, utiliser le navigateur Firefox.
🌐 TD à télécharger : Fichier arbre_dico_2022_sujet.ipynb
: "Clic droit", puis "Enregistrer la cible du lien sous"
⏳ La correction viendra bientôt ...
Crédits⚓︎
Gilles Lassus, Jean-Louis Thirot , Mireille Coilhac, Valérie Mousseaux, sur la base du travail de :
- David ROCHE publié sur Pixees
- Equipe éducative DIU EIL, Université de Nantes.
- Ressource d'accompagnement Eduscol sur les structures de données.
- Livre Prepabac NSI, Tle, G. Connan, V. Petrov, G. Rozsavolgyi, L. Signac, éditions HATIER.
# Tests
(insensible à la casse)(Ctrl+I)
(Ctrl+Clic pour inverser les colonnes)