Les arbres binaires¶
Warning
Ce cours a été automatiquement traduit des transparents de M.Noyer par Félix qui continue le travail fait par Lorentzo et Elowan et Mehdi, nous ne nous accordons en aucun cas son travail, ce site à pour seul but d'être plus compréhensible pendant les périodes de révision que des diaporamas.
Crédits
- "Option informatique MPSI, MP/MP* ", Roger Mansuy, paru chez Vuibert.
- Wikipédia, arbres binaires
- Un cours à Louis Le Grand
Introduction¶
Résumé¶
"Les arbres permettent la réalisation de structures de données : structure persistante de dictionnaire, structure persistante de file de priorité. Ils permettent aussi de représenter des expressions arithmétiques ou des formules logiques "(programme officiel CPGE 2013).
Figure 1 – Une arborescence de fichiers
Commentaire
La colonne de gauche est l'affichage arborescent de mon répertoire
Figure 2 – Contenu d'un fichier html
Commentaire
La colonne de gauche est le code d'un fichier
Figure 3 – Affichage html
Commentaire
La colonne de gauche est l'interprétation du fichier précédent par
Arithmétique¶
Figure 4 – Une expression arithmétique
Commentaire
La colonne de gauche est la représentation arborescente de
Logique¶
Figure 5 – Une expression logique
Commentaire
La colonne de gauche est la représentation arborescente de
Définition mathématique¶
Arbre binaire¶
Définition
Soient
: nil est un arbre binaire appelé arbre vide : Si et si , sont deux arbres binaires étiquetés par , alors est un arbre binaire étiqueté par . : Seuls nil et les éléments que l'on peut former en un nombre fini d'application des règles d'induction sont des arbres binaires.
Remarque
Un arbre est donc un élément d'un ensemble inductif (voir chapitre précédent). On fait le choix dans la suite de ne pas utiliser de symbole pour le constructeur ternaire : on écrira
Vocabulaire¶
Avec les conventions de la définition
Étiquette
Fils gauche / droit
Si
Père
On dit que
Feuille
Si
Remarque
Si \(A =
Chemin
Si
Sous-arbre
Dans un chemin, tous les
Noeud interne
Un nœud interne possède au moins un fils qui n'est pas l'arbre vide. Ce sont tous les nœuds d'un arbre à l'exception de nil et des feuilles.
Convention de représentation¶
Par convention, on ne représente ni nil, ni les arcs d'extrêmités nil. Au lieu de
Figure 6 – Avec nil
On représente
Figure 7 – Sans nil
Propriétés¶
Lemme
Dans un arbre, aucun chemin ne comporte deux fois un même arbre non vide.
Preuve
- Soit un chemin
tel que . - Par application du théorème sur l'ordre structurel (voir chapitre induction), les tailles structurelles (nombres de constructeurs) sont strictement décroissantes.
Ainsi
Types d'arbres binaires¶
- Certains arbres ne sont pas binaires. Exemple : la figure
. - Un arbre binaire entier est un arbre dont tous les nœuds possèdent zéro ou deux fils (ex : la figure
mais pas ). - Un arbre binaire parfait est un arbre binaire entier dans lequel toutes les feuilles sont à la même distance de la racine (c'est-à-dire à la même profondeur) (ex : la figure
). - L'arbre binaire parfait est parfois nommé arbre binaire complet. Cependant certains auteurs
définissent un arbre binaire complet comme étant un arbre binaire entier dans lequel les feuilles ont pour profondeur soit soit pour un donné (voir figure ).
Arbres binaires¶
Figure 8 – Un arbre binaire parfait
Tous les niveaux sont remplis.
Figure 9 – Un arbre binaire complet gauche
Tous les niveaux sont complets sauf le dernier qui est rempli incomplètement en commençant par la gauche.
Preuve par induction¶
Ordre sur les arbres binaires¶
La relation binaire
C'est un ordre bien fondé et
Démonstration
Un descendant est un sous-terme. Donc cet ordre n'est rien d'autre que l'ordre structurel (voir chapitre induction) lequel est bien fondé.
Eléments sans prédecesseur de ¶
Proposition
L'ensemble des éléments sans prédecesseur des arbres étiquetés par
Preuve
Soit un arbre A.
- Si
nil, il n'a pas de prédécesseur car le constructeur est d'arité . - Sinon,
est de la forme ( ) et donc . Donc admet un prédécesseur.
Principe d'induction appliqué aux arbres¶
Soit
- On établit la propriété pour les éléments minimaux (donc
nil ). - On prend
avec prédécesseur. On suppose que pour tout prédécesseur de , est vrai, et on tente d'établir que est vrai.
Fonction inductives¶
Soit
Le principe d'induction établit que
Taille¶
Taille
La taille d'un arbre binaire est le nombre de ses nœuds qui ne sont pas nil
La taille d'un arbre
Remarque
Cette définition est différente de la taille structurelle vue au chapitre induction en ce sens qu'elle ne compte pas les constructeurs d'arité
Profondeur¶
Hauteur
La hauteur d'un arbre binaire est la longueur de la plus longue branche (sans arriver jusqu'à nil).
La hauteur d'un arbre binaire
Profondeur
La profondeur d'un nœud dans un arbre binaire est la longueur du chemin qui le relie à la racine.
Remarque
Là encore, la définition varie selon les auteurs.
Un type pour les arbres binaires¶
Hauteur et taille¶
- On observe d'abord que pour ces fonctions, la complexité au pire est croissante avec la taille de la variable.
- En effet, soit
un arbre avec nœuds qui atteint le maximum de complexité. Pour ( , ,nil), qui a nœuds, le calcul nécessite au moins une opération de plus (ne serait-ce que le filtrage).
Complexité du calcul de la hauteur¶
Méthode informelle¶
Pour un arbre de taille
- De façon empirique on peut dire que chaque nœud est parcouru trois fois : quand on y accède (au moment du filtrage), quand le parcours revient du fils gauche (avec l'info sur sa hauteur), quand il revient du fils droit (avec l'info sur sa hauteur).
- Pour chacun de ces trois passages dans le nœud, le nombre d'opérations élémentaires hors appels récursifs est borné par une constante (disons
). - Au total, on peut donc majorer le nombre d'opérations par
et le minorer par . - Donc complexité en
Relation entre taille et hauteur¶
Proposition
Soit
Preuve par induction
- Si
nil, alors ; OK - Si
, et si la propriété est vraie pour , , alors
Et
Donc
Les deux bornes sont atteintes : à gauche par les listes chaînées et à droite par les arbres parfaits.
Profondeur moyenne et applications¶
Profondeur moyenne¶
La profondeur moyenne d'un arbre est la moyenne des longueurs de ses branches ou encore la moyenne des profondeurs des feuilles.
Proposition
Dans un arbre binaire à
Cas de base¶
Par récurrence sur le nombre de feuille
- Vrai pour
(profondeur au moins zéro, ).
- Si
, la plus petite profondeur moyenne intervient quand les deux feuilles sont à la profondeur . Alors la profondeur moyenne vaut et . Si l'une des feuilles n'est pas à la profondeur , la profondeur moyenne est strictement supérieure à .
Cas d'un fils unique¶
Par récurrence sur le nombre de feuille
- L'unique fils
de a autant de feuilles que mais la profondeur de ses feuilles est plus petite (car ). - En descendant dans l'arbre on finit par trouver un premier descendant
qui a deux fils (car a au moins deux feuilles) et feuilles. - On montre donc la propriété pour
, elle sera vraie pour car la profondeur moyenne y est plus grande.
Deux fils et feuilles¶
On suppose que
Relation moyenne
On a à gauche :
Notation
= profondeur de la feuille i du fils gauche, moyenne des profondeurs à gauche.
Gauche :
Droite :
La somme des profondeurs des feuilles dans
La somme
La fonction
Cette dérivée s'annule en
Par suite
Donc
Alors la moyenne
Donc
Application aux tris¶
Permutation associée à une liste¶
Considérons un tri
- Considérons une liste (ou un tableau) à
nombres . La complexité du tri sur cette structure ne dépend pas des valeurs de ces nombres mais de l'ordre initial dans lequel ils sont placés. - Classer
a la même complexité que le classement de (permutation d'éléments dans J1,nK). - A une liste
de nombres distincts à trier, on associe ainsi une unique permutation . Le coût du tri de selon l'algorithme dépend seulement de (ordre des éléments) et on le note donc .
Complexité en moyenne¶
Complexité en moyenne
La complexité en moyenne
Arbre de décision¶
Arbre de décision
Un arbre de décision est un arbre binaire tel que
- chaque nœud interne est étiqueté avec une comparaison,
- chaque feuille est étiquetée avec une permutation
A un algorithme de tri appliqué à des listes de taille
On construit ainsi cet arbre de décision : La racine est la première comparaison observée entre éléments. Son fils gauche est la première comparaison effectuée lorsque le test correspondant à la racine est positif, le droit est la première comparaison effectuée si le premier test est négatif etc.
L'arbre de décision associé à un tri par comparaison sur des structures
de longueur
Arbre de décision du tri par insertion pour les listes
Complexité en moyenne à partir de l'arbre de décision¶
Soit un tri
- La complexité du tri par
d'une liste de longueur est proportionnelle à la longueur de la branche de A empruntée en traitant L.
Si
- La complexité en moyenne de
est donc proportionnelle à la profondeur moyenne des feuilles. - Or, celle-ci est minorée par
Et la formule de Stirling nous donne . - Ainsi, la meilleure complexité possible en moyenne pour un tri par comparaison est
. - La complexité au pire est supérieure à la complexité en moyenne. Un algorithme qui, comme le tri fusion, réalise une complexité au pire en
est donc un algorithme de tri par comparaison optimal.
Parcours d'arbres binaires¶
Objectif¶
Un parcours d'arbre est une façon d'ordonner les nœuds d'un arbre afin de tous les parcourir.
On peut le voir comme une fonction qui à un arbre associe une liste de ses nœuds même si la liste n'est souvent pas explicitement construite par le parcours.
Parcours en profondeur¶
Depth-first search (DFS)¶
Les parcours en profondeur se définissent de manière récursive sur les arbres. Le parcours d'un arbre consiste à traiter la racine de l'arbre et à parcourir récursivement les sous-arbres gauche et droit de la racine. Les parcours préfixe, infixe et suffixe se distinguent par l'ordre dans lequel sont faits ces trois traitements.
Figure – Ordre dans lequel les nœuds sont visités (en exposant) dans un parcours en profondeur préfixe. Les lettres correspondent à la numérotation par parcours en largeur.
Type OCAML (rappel)¶
Il y a beaucoup de façon de définir les arbres binaires en Ocaml. En voici une :
Parcours préfixe¶
Principe
Dès qu'on passe par un nœud, on effectue un traitement de son étiquette. On n'attend pas que les descendants du nœud soient traités. On fait ce qu'on a à faire avec ce nœud dès qu'on passe dessus.
On obtient 1 2 3 4 3 6 7.
Parcours suffixe¶
Principe
Quand on passe sur un nœud, on attend que tous ses descendants soient traités avant d'agir sur ce nœud.
On obtient 3 4 2 6 7 5 1
Parcours infixe¶
Principe
Quand on passe sur un nœud, on traite d'abord le fils gauche. Puis on traite le nœud lui même. Et enfin on traite le second fils.
On obtient 3 2 4 1 6 5 7
Compléments¶
La complexité du parcours en profondeur pour un arbre a déjà été étudiée : c'est celle du calcul de la hauteur (laquelle est un parcours suffixe dans notre code puisque le traitement a lieu lorsqu'on connaît la hauteur des
Le parcours préfixe (resp. suffixe) est injectif (si l'on considère que Node(Nil,x,f)=Node(f,x,Nil)). Voir TD.
Parcours en largeur¶
BFS¶
L'algorithme de parcours en largeur (ou BFS, pour Breadth First Search en anglais) permet le parcours d'un arbre de la manière suivante : on commence par explorer un nœud source, puis tous ses fils, puis les fils des fils, etc.
En bref, on visite complètement une génération avant de visiter la génération suivante.
Un BFS
La dénomination des nœuds suivants respecte le parcours en largeur :
BFS vs DFS
La dénomination des nœuds suivants respecte le parcours en profondeur (prefixe) :
Deux fonctions auxiliaires¶
Liste des étiquettes des racines d'une forêt (i.e. un ens. d'arbres) :
Liste des fils des racines d'une forêt (si ce sont des nœuds internes).
Principe du parcours en largeur¶
La fonction sons retourne une forêt, label_list retourne la liste des étiquettes de la forêt.
La fonction bfs utilise la fonction aux qui prend une forêt et concatène la liste de ses étiquettes avec la liste des étiquettes des fils des racines.
bfs | |
---|---|
Complexité : chaque étiquette est ajoutée une fois et une seule à la liste résultat,
Dans ce qui suit on note
Complexité du parcours en largeur¶
Pour un arbre à
- La fonction qui récupére les étiquettes des racines d'une forêt
et celle qui récupère les fils sont de complexité . - A chaque étape, on récupère la liste des étiquettes des sous-arbres d'une même profondeur et on l'ajoute au résultat.
- Lorsqu'on traite la liste des nœuds de profondeurs
(disons qu'il y en a ) :- on récupère la liste de leurs étiquettes en
; - on les concatènes à gauche du résultat de l'appel récursif en
; - la liste des fils des nœuds de profondeur
s'obtient aussi en . - A ceci s'ajoute le coût de l'appel interne.
- on récupère la liste de leurs étiquettes en
- La complexité
vérifie donc une relation de la forme : . . - Au départ
(nombre de nœuds à la profondeur : racine) et avec la hauteur et qui correspond au traitement de la liste vide (pas de nœud à la profondeur ). - On somme sur les profondeurs allant de
(la racine) à (la hauteur de l'arbre). C'est une série telescopique. On obtient :
La complexité est proportionnelle au nombre de nœuds : on aurait pu s'en douter !