Comment réaliser et utiliser un arbre binaire ?
Les arbres binaires (en anglais, binary trees) permettent une organisation hiérarchique des données. Ceci leur confère souvent un avantage dans un parcours à la recherche d'une donnée, en comparaison de simple vecteurs. D'autre part, de très nombreux problèmes se prêtent bien à être vus comme des problèmes d'arbres. Les problèmes présentant naturellement une structure hiérarchique (pyramide d'une entreprise, arbres syntaxiques abstraits d'un compilateur, arborescence de fichiers), la réalisation de tris. Ceci fait la relative popularité de cette structure de données dans un grand nombre de cas. Structure d'un arbre binaireUn arbre binaire est constitué d'un ensemble de noeuds. Chaque noeud possède une référence vers au plus deux autres noeuds. Ces noeuds sont appelés noeuds enfants et sont souvent distingués en tant que fils gauche et fils droit. Chaque noeud contient de plus une donnée à conserver et optionnellement une référence vers son noeud parent. Un noeud particulier est le noeud dit racine de l'arbre. C'est le seul noeud à ne pas avoir de parent. Décrire l'arbre revient à en connaître le noeud racine. L'ensemble des référents vers les noeuds fils permet ainsi d'accéder, à partir de la racine, à tout noeud de l'arbre. Les notions suivantes sont fréquemment utilisées : - La profondeur d'un noeud est sa distance à la racine
- La hauteur de l'arbre est la taille du chemin le plus long qu'il est possible de parcourir dans l'arbre
- Les frères (en anglais, Siblings) d'un noeud sont l'ensemble des noeuds possédant le même parent.
- Un noeud ne possédant pas de fils est appelé feuille.
Les noeuds peuvent être décrits de manière différente. On utilisera généralement soit un système de référents offerts par l'utilisation d'objets au travers des instructions New et Set, ou alors un vecteur de types définis dont les indices serviront de référents. VariantesLes arbres binaires de recherche (encore appelés arbres binaires de fouille ou arbre binaires ordonnés) sont des arbres binaires tels que la valeur associée à un noeud parent est supérieure à toute valeur présente dans sa branche gauche et inférieure à toute valeur présente dans sa branche droite. Ces arbres sont, de par leur nature, toujours triés. L'insertion et la suppression d'un noeud dans un tel arbre est rapide, ce qui en fait une structure utile pour conserver triée une liste dynamique de données. L'arbre binaire n'est en réalité qu'une particularisation d'un arbre n-aire. Un arbre n-aire contient des noeuds possédant au plus n noeuds fils. RéalisationL'implémentation suivante d'un arbre binaire utilise un vecteur comme structure de données sous-jacente. Data est choisi de type Long. Il est bien entendu possible d'implémenter la même structure pour stocker tout autre type de données. Les méthodes sont les suivantes : - SetValue(Node, Data) : Définit la donnée (Data) associée au noeud Node
- GetValue(Node) : Retrouve la donnée associée au noeud Node
- SetLeft(Node, Data) : Associe au noeud Node un fils gauche possédant la donnée Data
- SetRight(Node, Data) : Associe au noeud Node un fils droit possédant la donnée Data
- ClearLeft(Node) : Supprime le fils gauche du noeud Node
- ClearRight(Node) : Supprime le fils droit du noeud Node
- GetLeft(Node) : Retrouve le fils gauche du noeud Node
- GetRight(Node) : Retrouve le fils gauche du noeud Node
Les points importants afin de comprendre l'implémentation sont les suivants : - la présence du type utilisateur Node, permettant de décrire un noeud de l'arbre
- la suppression récursive des noeuds par ClearNode des méthodes récursives sont très souvent utilisées pour réaliser des opérations sur des arbres
- la gestion des descendants et en particulier l'utilisation de NODE_INVALIDREF lorsque ceux-ci sont indéfinis
Le module de classe BinaryTree réalise un arbre binaire : Option Explicit
Private Type Node Left As Long Right As Long Value As Long InUse As Boolean End Type
Private Const MAX_NODES As Long = 1024 Private Const NODE_INVALIDREF As Long = -1
Private mNextFreeNode As Long Private mNodes(MAX_NODES) As Node
Private Sub Class_Initialize() CreateNode 0 End Sub
Private Sub Class_Terminate() Erase mNodes End Sub
Private Sub GetNextFreeNode() Dim i As Long Dim TempValue As Long TempValue = -1 For i = mNextFreeNode To MAX_NODES If mNodes(i).InUse = False Then TempValue = i Exit For End If Next mNextFreeNode = TempValue End Sub
Private Sub ClearNode(Node As Long) If (Node <> NODE_INVALIDREF) Then ClearNode (mNodes(Node).Left) ClearNode (mNodes(Node).Right) mNodes(Node).InUse = False If (mNextFreeNode > Node) Then mNextFreeNode = Node End If End If End Sub
Private Function CreateNode(Value As Long) As Long If (mNextFreeNode = -1) Then Err.Raise 7 End If
mNodes(mNextFreeNode).Value = Value mNodes(mNextFreeNode).Left = NODE_INVALIDREF mNodes(mNextFreeNode).Right = NODE_INVALIDREF mNodes(mNextFreeNode).InUse = True CreateNode = mNextFreeNode GetNextFreeNode End Function
Public Function GetValue(Node As Long) As Long GetValue = mNodes(Node).Value End Function
Public Function SetValue(Node As Long, Value As Long) mNodes(Node).Value = Value End Function
Public Function GetLeft(Node As Long) As Long GetLeft = mNodes(Node).Left End Function
Public Function SetLeft(Node As Long, Value As Long) As Long SetLeft = CreateNode(Value)
ClearLeft Node mNodes(Node).Left = SetLeft End Function
Public Sub ClearLeft(Node As Long) ClearNode mNodes(Node).Left mNodes(Node).Left = NODE_INVALIDREF End Sub
Public Function GetRight(Node As Long) As Long GetRight = mNodes(Node).Right End Function
Public Function SetRight(Node As Long, Value As Long) As Long SetRight = CreateNode(Value)
ClearNode (mNodes(Node).Right) mNodes(Node).Right = SetRight End Function
Public Sub ClearRight(Node As Long) ClearNode mNodes(Node).Right mNodes(Node).Right = NODE_INVALIDREF End Sub
La fonction suivante présente un exemple d'utilisation : Option Explicit
Private Sub Form_Load() Dim Tree As BinaryTree Dim NewNode As Long Set Tree = New BinaryTree Tree.SetValue 0, 0 NewNode = Tree.SetRight(0, 6) Tree.SetLeft NewNode, 7 Tree.SetRight NewNode, 8 NewNode = Tree.SetLeft(0, 3) Tree.SetValue NewNode, 1 Tree.SetRight NewNode, 2 Tree.ClearRight NewNode NewNode = Tree.SetLeft(NewNode, 2) Tree.SetLeft NewNode, 3 NewNode = Tree.SetRight(NewNode, 4) Tree.SetLeft NewNode, 5 ShowTree Tree End Sub
Private Sub ShowTree(Tree As BinaryTree, Optional Node As Long = 0, Optional Level As Long = 0) Dim i As Long
If Level >= 0 And Node >= 0 Then For i = 1 To Level - 1 Debug.Print "|", Next i If (Level > 0) Then Debug.Print "+-----------"; End If Debug.Print Tree.GetValue(Node) ShowTree Tree, Tree.GetLeft(Node), Level + 1 ShowTree Tree, Tree.GetRight(Node), Level + 1 End If End Sub
Pour aller plus loin Voir aussi : |