0% ont trouvé ce document utile (0 vote)
27 vues29 pages

Arbres Et Structure de Données

Le document présente les arbres comme des structures de données hiérarchiques, en détaillant leur définition, leurs éléments constitutifs, et leurs types, notamment les arbres binaires et les arbres binaires de recherche. Il aborde également les mesures de taille et de hauteur des arbres, ainsi que les méthodes d'implémentation et de parcours. Enfin, il souligne l'importance des arbres dans divers contextes informatiques, comme l'organisation des systèmes de fichiers et le modèle DOM du web.

Transféré par

Emmanuel
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
27 vues29 pages

Arbres Et Structure de Données

Le document présente les arbres comme des structures de données hiérarchiques, en détaillant leur définition, leurs éléments constitutifs, et leurs types, notamment les arbres binaires et les arbres binaires de recherche. Il aborde également les mesures de taille et de hauteur des arbres, ainsi que les méthodes d'implémentation et de parcours. Enfin, il souligne l'importance des arbres dans divers contextes informatiques, comme l'organisation des systèmes de fichiers et le modèle DOM du web.

Transféré par

Emmanuel
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats DOCX, PDF, TXT ou lisez en ligne sur Scribd

Arbres et structure de données

🙃 Ce contenu est proposé pour la classe de Terminale. Revenir à ma


classe de CP

Arbres et structure de données

FICHE DE COURS

Introduction :

Les arbres sont des structures de données hiérarchiques. Les cas


d’usage des arbres peuvent être très variés, et de nombreux
utilisateur·rice·s des outils numériques interagissent avec des arbres
sans nécessairement en avoir conscience.
Nous allons, dans une première partie, caractériser ces structures, en
illustrer différents usages, et porter une attention plus particulière aux
arbres binaires, sur lesquels nous étudierons des implémentations
algorithmiques dans les parties suivantes. Nous effectuerons, en
deuxième partie, des mesures et parcours sur ces arbres binaires, et
nous implémenterons en troisième partie des recherches et ajouts de
valeurs dans des arbres binaires de recherche.

Caractérisation des arbres


Un arbre est une structure de données liant entre eux des nœuds par
l’intermédiaire d’arêtes formant des branches. Contrairement aux
graphes , qui font l’objet d’un cours séparé dans ce chapitre, l’organisation
des nœuds d’un arbre comporte une dimension hiérarchique.
Définition
Arbre :

Un arbre est une structure de données composée de nœuds reliés entre


eux par des branches, selon une organisation hiérarchique, à partir d’un
nœud racine.
Commençons par présenter les différents éléments constitutifs d’un arbre.

Éléments constitutifs d’un arbre


Un arbre est constitué d’un élément de base : son nœud racine.
De ce nœud racine peuvent ensuite partir des arêtes reliant d’autres
nœuds, lesquels peuvent eux-mêmes relier d’autres nœuds pour former
des branches.

 Dans le sens descendant depuis la racine, les nœuds reliés aux


niveaux supérieurs sont
appelés nœuds enfants ou nœuds fils du nœud dont ils
dépendent.
 Inversement un nœud enfant est rattaché dans le sens ascendant
à un nœud père ou nœud parent.

Astuce
Seul le nœud racine n’a pas de père.
Un nœud n’ayant pas de nœuds enfants est dit nœud terminal. Situé à
l’extrémité d’une branche, il est également appelé « feuille ».

Chaque nœud peut stocker une information, appelée valeur ou clé du


nœud.

Un sous-arbre est une portion d’arbre à partir d’un nœud quelconque qui
constitue la racine de ce sous-arbre.
 Une structure de données organisée comme un arbre est dont dite
« arborescente ».

Sa représentation graphique évoque la forme d’un arbre végétal, à ceci


près que les arbres informatiques sont généralement représentés avec la
racine tout en haut du schéma, pour mieux traduire cette notion de
hiérarchie descendante depuis le nœud racine.

Représentation de la

structure d’un arbre


Contextes d’emploi des arbres
Les structures de type arbre sont très présentes en informatique.
L’organisation du système de fichiers d’un ordinateur est arborescente. Les
fichiers sont organisés de manière hiérarchique à partir d’une racine, à
laquelle peuvent être rattachés des répertoires (parfois appelés dossiers) et
des fichiers, les répertoires pouvant eux-mêmes de manière récursive
contenir d’autres répertoires et/ou fichiers.
Organisation arborescente d’un système de fichiers

On trouve également des arbres dans le contexte du web.


Le DOM (Document Object Model) ou « modèle objet de document » du
langage HTML représente un document web de manière structurée sous
forme d’un arbre hiérarchique.
Code source et modèle objet de document (DOM) d’un même document HTML
Types d’arbres
Il existe différentes sortes d’arbres :

 les
arbres généraux peuvent posséder un nombre variable de
branches ;
 les
arbres binaires et les arbres binaires de recherche sont
caractérisés par des propriétés particulières.
 Arbre binaire

Définition
Arbre binaire :

Un arbre binaire est un arbre dont chaque nœud comporte au plus deux
sous-arbres enfants.
Les sous-arbres d’un arbre binaire sont conventionnellement appelés
« sous-arbre gauche » et « sous-arbre droit », ou encore « branche
gauche » et « branche droite ». Voire, plus simplement, gauche et droit.

Chaque nœud de l’arbre binaire comporte au maximum deux sous-arbres.


Exemple d’arbre binaire

Astuce
 Certains nœuds non terminaux peuvent n’avoir qu’une seule
branche.
 Lesbranches d’un arbre ou d’un sous-arbre binaire ne sont pas
nécessairement de longueurs égales.
 Arbre binaire de recherche

Un arbre binaire de recherche est un cas particulier d’arbre binaire qui se


distingue par le caractère ordonné des nœuds qui le composent.

Définition
Arbre binaire de recherche :

Un arbre binaire de recherche est un arbre binaire dont les clés sont
ordonnées.

Définition
Clé (d’un nœud) :
La clé d'un nœud correspond à la valeur qui lui est affectée.

 Parexemple, la clé de la racine de l'arbre binaire de recherche


donné ci-dessous est 1212.

Le placement des clés est effectué de manière à toujours maintenir le


caractère ordonné de l’arbre binaire de recherche :

 les valeurs situées ou ajoutées dans le sous-arbre gauche


d’un arbre binaire de recherche sont nécessairement
inférieures à celle de la clé du nœud considéré ;
 les valeurs situées ou ajoutées dans le sous-arbre droit d’un
arbre binaire de recherche sont nécessairement supérieures
à celle de la clé du nœud considéré.

Exemple d’arbre binaire

de recherche

Exemple
Pour ajouter 1313, on doit nécessairement l'ajouter dans le sous-arbre droit
en considérant la racine car 13>1213>12. Dans le sous-arbre
droit, 1414 étant la racine, 1313 sera alors dans le sous-sous-arbre
gauche puisque 13<1413<14. Sachant qu'il n'existe pas encore ces sous-
sous-arbre gauche, 1313 en sera la racine.
Mesures sur les arbres
Les arbres peuvent comporter plus ou moins de nœuds et de branches de
longueurs variables. On peut mesurer la taille et la hauteur des arbres.

Définition
Taille d’un arbre :

La taille d’un arbre est le nombre de nœuds qu’il comporte (incluant bien
sûr le nœud racine).

Exemple
La taille de l’arbre binaire de recherche ci-avant est de 5.

Définition
Hauteur d’un arbre :

La hauteur, parfois appelée « profondeur », correspond au nombre de


nœuds parcourus sur le plus long chemin possible depuis la racine de
l’arbre, sans revenir sur ses pas.

Exemple
La hauteur de l’arbre binaire de recherche ci-avant est de 3.
Les structures de type arbre peuvent être implémentées de différentes
manières. Le paradigme de programmation orientée objet est généralement
employé, avec un recours fréquent à l’approche récursive pour les
méthodes.
Nos implémentations dans les parties suivantes du cours suivront ces
pratiques usuelles, étant précisé qu’il est également possible d’employer le
paradigme fonctionnel et des approches itératives.
Implémentations sur des arbres binaires
Cette deuxième partie est consacrée aux implémentations sur des arbres
binaires.
Après avoir conçu des classes adaptées à ces implémentations, nous
calculerons taille et hauteur, avant d’effectuer différents parcours des
arbres binaires.

Conception des classes


Notre implémentation des arbres binaires repose sur deux classes
distinctes :

 une classe modélisant des nœuds ;


 une classe modélisant des arbres binaires à partir des nœuds.
 Classe Noeud

La classe Noeud définit des objets composés d’une valeur (la clé du nœud)
et de deux branches, la gauche et la droite, identifiées par leur nœud racine
.

class Noeud:

def __init__(self, cle):

[Link] = cle
[Link] = None
[Link] = None

À retenir
Les modalités de création d’un nœud sont précisées dans la définition de la
méthode spéciale __init__ :

 seule la valeur de la clé doit être précisée au moment de la


création d’un nœud ;
 ses sous-branches sont initialisées avec l’objet None , qui exprime
l’absence de valeur.

La création d’un nœud s’effectue ainsi :

noeud = Noeud('A')

Affichons les attributs du nœud.

print(noeud)
print([Link])
print([Link])
print([Link])

affiche successivement :

__main__.Noeud object at 0x10b215278> # (adresse mémoire attribuée


dynamiquement à la création de l'objet)
A
None
None

Les attributs de l’objet peuvent ensuite être modifiés.

Exemple
Ajout de deux nœuds enfants aux sous-branches du nœud initial.

[Link] = Noeud('B')
[Link] = Noeud('C')

print(noeud)
print([Link])
print([Link])
print([Link])

affiche successivement:

<__main__.Noeud object at 0x10b215278>


A
<__main__.Noeud object at 0x10b1ec588>
<__main__.Noeud object at 0x10b1ec630>

 Les nœuds B et C sont bien affectés aux deux sous-branches du


nœud A.

Notons que pour afficher la valeur des clés gauche et droite, il suffit
d'employer les commandes suivantes :

print([Link])
print([Link])

Ce qui affichera successivement


B
C
 Classe ArbreBinaire

La classe ArbreBinaire définit des objets composés initialement d’un


nœud racine, auquel pourront être rattachés des nœuds aux différentes
sous-branches.

class ArbreBinaire:

def __init__(self, racine):

[Link] = Noeud(racine)

La création d’un arbre binaire s’effectue par initialisation de l’arbre avec un


nœud racine.
ab = ArbreBinaire('A')

On peut ensuite ajouter des nœuds aux branches du nœud racine, puis aux
nœuds qui y sont rattachés, sans limitation de profondeur.

[Link] = Noeud('B')
[Link] = Noeud('C')

[Link] = Noeud('D')
[Link] = Noeud('E')

[Link] = Noeud('F')
[Link] = Noeud('G')

Représentation de l’arbre

nommé « ab »

Une implémentation plus complète pourrait intégrer la possibilité d’ajout, de


modification et de suppression de nœuds de l’arbre par des méthodes
dédiées. Nous implémenterons l’ajout d’un élément sur un arbre binaire de
recherche dans la troisième partie du cours.
Dans cette partie, nous nous intéressons en priorité aux mesures de taille
et de profondeur, ainsi qu’aux modalités de parcours des arbres binaires.
Taille d’un arbre binaire
Déterminer la taille d’un arbre revient à compter l’ensemble des nœuds
composant cet arbre. Nous effectuons ce compte à partir du nœud racine,
en explorant récursivement tous les sous-arbres de chacun des nœuds.

class ArbreBinaire:

def __init__(self, racine):

[Link] = Noeud(racine)

def taille(self, noeud='racine'):

if noeud == 'racine':

noeud = [Link]

if not noeud:

return 0

else:

return 1 + [Link]([Link]) + [Link]([Link])

À retenir
La méthode taille est définie avec comme paramètres :

 self qui désigne l’instance de la classe ;


 le nœud à traiter.

L’appel initial est effectué avec une valeur par défaut correspondant au
nœud racine de l’arbre. Les appels suivants sont effectués de manière
récursive sur les sous-arbres, dont le nombre de nœuds est ajouté au
nœud courant. La récursion s’arrête en l’absence de nœud en sous-arbre.

Exemple
Appel de la méthode sur l’arbre binaire nommé ab :

print([Link]())
# affiche 7

Vérifions que notre méthode de détermination de taille fonctionne


également sur un arbre binaire dont toutes les branches ne sont pas
pareillement développées.

# arbre binaire incomplet


abi = ArbreBinaire('A')
[Link] = Noeud('B')
[Link] = Noeud('C')
[Link] = Noeud('D')
[Link] = Noeud('E')
Représentation

graphique de l’arbre nommé « abi »

print([Link]())
# affiche 5

Implémentons maintenant une méthode déterminant la hauteur d’un arbre


binaire.

Hauteur d’un arbre binaire


Nous employons la même approche récursive que pour le calcul de la taille.

class ArbreBinaire:

def __init__(self, racine):

[Link] = Noeud(racine)

def hauteur(self, noeud='racine'):

if noeud == 'racine':

noeud = [Link]

if not noeud:
return 0

else:

return 1 + max([Link]([Link]), [Link]([Link]))

À retenir
Comme précédemment, la méthode hauteur est définie avec comme
paramètres :

 self qui désigne l’instance de la classe ;


 le nœud à traiter.

Les retours des appels récursifs sur les sous-branches gauches et droites
sont passés en arguments à la fonction max , laquelle retourne la plus
grande des valeurs fournies, de manière à pouvoir déterminer la hauteur de
tout type d’arbre binaire.

Exemple
Appel de la méthode hauteur sur les deux arbres binaires
précédents ab et abi :

print([Link]())
# affiche 3

print([Link]())
# affiche 4

La hauteur est correctement déterminée pour les deux arbres.

 L’arbre ab présente la particularité que toutes ses branches sont


de longueur égale.
 Les sous-branches de l’arbre abi sont en revanche de longueurs
inégales, mais c’est bien la plus grande des branches qui est
prise en compte.

Intéressons-nous maintenant aux parcours des arbres binaires.

Parcours des arbres binaires

Définition
Parcours d’un arbre :

Parcourir un arbre consiste à explorer l’ensemble de ses nœuds.


Il existe différentes méthodes pour effectuer cette exploration. Nous
implémentons ici trois modes de parcours des arbres binaires :

 le parcours préfixe ;
 le parcours infixe ;
 le parcours suffixe.

Les trois modes se distinguent par l’ordre dans lequel le parcours est
effectué sur les nœuds et leurs branches. Nous l’illustrons avec l’exemple
ci-après :

Exemple
Considérons l’arbre suivant :

Arbre binaire composé de trois nœuds dont les clés sont A, B et C.

 Le parcours préfixe consiste à parcourir d’abord le nœud racine,


puis le nœud gauche, et ensuite le nœud droit. Le parcours
préfixe de l’arbre s’effectue dans l’ordre A \rightarrow→ B \
rightarrow→ C.
 Le parcours infixe consiste à parcourir d’abord le nœud gauche,
puis le nœud racine, et ensuite le nœud droit. Le parcours infixe
de l’arbre s’effectue dans l’ordre B \rightarrow→ A \
rightarrow→ C.
Le parcours suffixe consiste à parcourir d’abord le nœud gauche, puis, le
nœud droit et ensuite le nœud racine. Le parcours suffixe de l’arbre
s’effectue dans l’ordre B \rightarrow→ C \rightarrow→ A.
Ces modes de parcours s’appliquent récursivement.

 Parcours préfixe

Commençons par implémenter le parcours préfixe.

class ArbreBinaire:

def __init__(self, racine):

[Link] = Noeud(racine)

def parcours_prefixe(self, position='racine', parcours=None):

if parcours is None:

parcours = []

if position == 'racine':

position = [Link]

if position:
parcours += [Link]
parcours = self.parcours_prefixe([Link], parcours)
parcours = self.parcours_prefixe([Link], parcours)

return parcours

Le parcours est enregistré dans une liste qui est complétée au fur à mesure
des appels récursifs du parcours.
L’appel de la méthode sur le nom de l’arbre retourne la liste des nœuds
dans l’ordre dans lequel ils ont été visités.

Légende

print(ab.parcours_prefixe())
# affiche ['A', 'B', 'D', 'E', 'C', 'F', 'G']

 Parcours infixe

Implémentons maintenant la méthode de parcours infixe.

class ArbreBinaire:

def __init__(self, racine):

[Link] = Noeud(racine)
def parcours_infixe(self, position='racine', parcours=None):

if parcours is None:

parcours = []

if position == 'racine':

position = [Link]

if position:

parcours = self.parcours_infixe([Link], parcours)


parcours += [Link]
parcours = self.parcours_infixe([Link], parcours)

return parcours

Légende

print(ab.parcours_infixe())
# affiche ['D', 'B', 'E', 'A', 'F', 'C', 'G']

 Parcours suffixe

Implémentons enfin la méthode de parcours suffixe.


class ArbreBinaire:

def __init__(self, racine):

[Link] = Noeud(racine)

def parcours_suffixe(self, position='racine', parcours=None):

if parcours is None:

parcours = []

if position == 'racine':

position = [Link]

if position:

parcours = self.parcours_suffixe([Link], parcours)


parcours = self.parcours_suffixe([Link], parcours)
parcours += [Link]

return parcours

Légende
print(ab.parcours_suffixe())
# affiche ['D', 'E', 'B', 'F', 'G', 'C', 'A']

Nous observons que les méthodes des trois parcours reposent sur la même
logique d'appels récursifs des différentes branches, dans un ordre
spécifique à chaque parcours.

Passons maintenant à des implémentations concernant plus


spécifiquement les arbres binaires de recherche.

Implémentations sur les arbres binaires de recherche


Cette troisième partie est consacrée à des implémentations sur des arbres
binaires de recherche ; les clés de leurs nœuds ont la particularité d’être
ordonnées. Nous allons tirer parti de cette spécificité dans notre
implémentation de fonctionnalités de recherche et d’insertion.

Conception des classes


Notre implémentation des arbres binaires de recherche repose sur deux
classes distinctes :

 une classe modélisant des nœuds ;


 une classe modélisant des arbres binaires de recherche à partir
des nœuds.

Astuce

Cette implémentation s’appuie sur la même classe de nœuds que celle


utilisée en deuxième partie, et sur une classe spécifique aux arbres
binaires de recherche.
Nous nous abstenons volontairement de recourir à l’héritage entre
classes afin de permettre l’étude des arbres binaires et des arbres
binaires de recherche de manière indépendante.
 Classe Noeud

class Noeud:

def __init__(self, cle):

[Link] = cle
[Link] = None
[Link] = None

class ArbreBinaireRecherche:

def __init__(self, racine):

[Link] = Noeud(racine)

Nous utilisons cette base pour instancier un arbre binaire de recherche.


Nous ajoutons quelques valeurs en veillant à respecter le caractère
ordonné de l’arbre. Nous utiliserons cet arbre pour effectuer nos
recherches, et nous implémenterons ensuite l’ajout de clé sous forme de
méthode déterminant l’emplacement d’insertion.

 Arbre binaire de recherche

abr = ArbreBinaireRecherche(12)

[Link] = Noeud(6)
[Link] = Noeud(14)

[Link] = Noeud(5)
[Link] = Noeud(7)
Représentation de l’arbre

nommé « abr »

Recherche de clé
La recherche de clé dans un arbre binaire de recherche exploite le
caractère ordonné des clés.

Nous définissons une méthode de recherche qui détermine, de manière


récursive à partir du nœud racine, si la clé du nœud courant correspond ou
non à la valeur recherchée. Si ce n’est pas le cas, elle compare la clé à la
valeur recherchée en évaluant si elle y est supérieure ou inférieure.

 Lesclés de l’arbre étant ordonnées, cela permet de déterminer


dans quel sous-arbre la valeur se situe nécessairement, si elle
est présente dans l’arbre.

class ArbreBinaireRecherche:

def __init__ (self, racine):

[Link] = Noeud(racine)

def recherche(self, valeur_recherchee, noeud=None):

if noeud is None:
noeud = [Link]

contenu = [Link]

if contenu == valeur_recherchee:

return True

elif contenu < valeur_recherchee:

if not [Link]:

return False

return [Link](valeur_recherchee, [Link])

else:

if not [Link]:

return False

return [Link](valeur_recherchee, [Link])

 Lafonction retourne True quand la valeur est trouvée,


et False quand elle est absente de l’arbre.

print([Link](12))
# affiche True

print([Link](9))
# affiche False

Le caractère ordonné de l’arbre permet d’éliminer un sous-arbre sur deux à


chaque étape. Nous avons utilisé des nombres pour les clés des nœuds,
mais notre code fonctionne également avec des caractères alphabétiques,
l’ordre appliqué étant dans ce cas l’ordre lexicographique (A est inférieur à
B qui est lui-même inférieur à C etc.).

La complexité de cet algorithme de recherche dans un arbre binaire de


recherche est d’ordre logarithmique, ce qui le rend efficace, y compris avec
des volumes importants de données.

Nous allons nous appuyer sur cette même logique pour l’implémentation de
l’insertion d’une nouvelle valeur dans l’arbre.

Ajout de clé
L’ajout d’une clé dans un arbre binaire de recherche doit s’effectuer de
manière à préserver le caractère ordonné des clés. On effectue donc une
démarche similaire à celle de la recherche, pour déterminer l’emplacement
auquel la nouvelle clé doit être insérée.

class ArbreBinaireRecherche:

def __init__(self, racine):

[Link] = Noeud(racine)

def ajoute(self, nouvelle_valeur, noeud=None):

if noeud is None:

noeud = [Link]

contenu = [Link]

if contenu == nouvelle_valeur:

return False

elif contenu < nouvelle_valeur:


if not [Link]:

[Link] = Noeud(nouvelle_valeur)
return True

return [Link](nouvelle_valeur, [Link])

else:

if not [Link]:

[Link] = Noeud(nouvelle_valeur)
return True

return [Link](nouvelle_valeur, [Link])

Notre implémentation s’assure par ailleurs que la clé qu’on cherche à


ajouter ne s’y trouve pas déjà.

 La méthode retourne True en cas d’insertion réussie,


et False dans le cas contraire, c'est-à-dire le cas où la valeur est
déjà présente dans l'arbre.

print([Link](18))
# affiche True

print([Link](7))
# affiche False
Représentation de l’arbre

binaire de recherche nommé « abr » après ajout de la valeur 18.

La position d’insertion de la nouvelle valeur est dictée par la propriété


ordonnée de l’arbre binaire de recherche, elle n’est donc pas spécifiée par
l’utilisateur·rice mais déterminée par l’algorithme. Dans le cas d’un arbre
binaire ou d’un arbre général, l’emplacement serait en revanche choisi par
l’utilisateur·rice.

Conclusion :

Nous avons caractérisé les structures de données hiérarchiques que


sont les arbres, dont les cas d’usage peuvent être très variés. Nous
avons porté une attention plus particulière aux arbres binaires, et
parmi eux aux arbres binaires de recherche. Nous avons ensuite
proposé l'implémentation de la détermination de la taille et de la
hauteur d’un arbre binaire, puis des méthodes pour leurs parcours de
manière préfixe, infixe et suffixe. Nous avons ensuite implémenté des
fonctionnalités de recherche et d’insertion de clé dans des arbres
binaires de recherche.
Je m’entraine ✍

Quiz

Tchat avec un prof

Vous aimerez peut-être aussi