Accéder au contenu principal

Arbre AVL : guide complet avec implémentation en Python

Un arbre AVL est un arbre binaire de recherche auto-équilibré où l’écart de hauteur entre les sous-arbres gauche et droit de tout nœud est d’au plus un, garantissant des opérations efficaces.
Actualisé 19 sept. 2026  · 15 min lire

Explorer avec l’IA

ChatGPTClaudePerplexity

Les arbres binaires de recherche (BST) sont une puissante structure de données pour organiser l’information, permettant des recherches et récupérations de valeurs efficaces. Toutefois, des BST classiques peuvent se déséquilibrer, ce qui dégrade les performances dans certains scénarios.

Les arbres AVL, nommés d’après leurs inventeurs Adelson-Velsky et Landis, résolvent ce problème en maintenant l’équilibre, quel que soit l’ordre d’insertion des données. Ils assurent ainsi des recherches constamment rapides, même sur de grands jeux de données.

À la fin de cet article, vous saurez implémenter un arbre AVL en Python et l’utiliser pour des recherches de données très performantes.

Cet article suppose que vous connaissez déjà les arbres binaires de recherche (BST), dont les arbres AVL sont une extension. Besoin d’un rappel ? Consultez cette courte introduction au Binary Search Tree (BST).

Avant d’approfondir les arbres AVL, voyons d’abord le problème qu’ils résolvent.

Devenez ingénieur en données

Développez vos compétences en Python pour devenir un ingénieur de données professionnel.
Commencez Gratuitement

Déséquilibre dans les arbres binaires de recherche

Les arbres binaires de recherche (BST) sont un type d’arbre binaire structure de données qui organise les données selon un ordre précis. Chaque nœud contient une valeur et possède des liens vers jusqu’à deux autres nœuds : les enfants gauche et droit. Dans un BST, la valeur de l’enfant gauche doit être inférieure à celle de son parent, et la valeur de l’enfant droit doit être supérieure.

Exemple d’arbre binaire de recherche avec 6 nœuds.

Les BST sont très efficaces pour retrouver des valeurs précises, car ils permettent d’éliminer de larges portions de l’arbre pendant la recherche. Par exemple, si nous cherchons la valeur un dans l’arbre ci-dessus, nous pouvons ignorer tous les nœuds à droite de six. En effet, la propriété d’ordre garantit que toutes ces valeurs sont supérieures à six.

Utiliser les propriétés d’ordre d’un BST pour chercher efficacement

Idéalement, chaque nœud doit scinder les données en deux, afin qu’à chaque niveau la moitié des valeurs soit éliminée. On obtient alors des recherches extrêmement rapides. Cependant, selon l’ordre d’insertion, on peut obtenir un arbre déséquilibré qui ne scinde pas efficacement les données. Par exemple, insérer des valeurs de la plus petite à la plus grande produit un arbre linéaire, qui n’est pas meilleur qu’une liste.

Exemple d’arbre binaire de recherche linéaire

Qu’est-ce qu’un arbre AVL ?

Un arbre AVL est un arbre binaire de recherche doté de la propriété supplémentaire suivante :

Pour chaque nœud, la hauteur des sous-arbres gauche et droit diffère d’au plus un.

Décomposons cette définition : le sous-arbre gauche d’un nœud regroupe tous les nœuds situés à sa gauche, tandis que le sous-arbre droit comprend tous les nœuds situés à sa droite. La hauteur d’un arbre est définie comme la longueur du plus long chemin entre la racine (le nœud supérieur) et l’une de ses feuilles (nœuds sans enfants).

Sous-arbre et hauteur dans un arbre binaire de recherche

Le facteur d’équilibre d’un nœud est calculé comme la différence de hauteur entre son sous-arbre gauche et son sous-arbre droit :

balance(N) = hauteur(sous-arbre gauche de N) - hauteur(sous-arbre droit de N)

Par exemple, balance(6) = 1 - 3 = -2.

Facteur d’équilibre dans un arbre binaire de recherche

Dans le schéma, le nœud 6 présente un facteur d’équilibre de -2, ce qui indique que l’arbre ne respecte pas les critères des arbres AVL. Pour qu’un arbre soit classé AVL, le facteur d’équilibre de chaque nœud doit être -1, 0 ou 1.

Pourquoi utiliser des arbres AVL

L’efficacité des requêtes dans un arbre binaire de recherche dépend de la hauteur de l’arbre. Dans le pire des cas, le nombre de nœuds à examiner est égal à cette hauteur. Un problème clé des BST est que la hauteur peut égaler le nombre de nœuds : une requête peut alors nécessiter d’examiner chaque nœud.

Hauteur au pire cas d’un BST

Notons M(h) le nombre minimal de nœuds à ajouter à un arbre binaire de recherche pour atteindre une hauteur h. Pour de simples BST, on observe que M(h) = h : on peut atteindre une hauteur h avec seulement h nœuds. Cela signifie que la hauteur d’un BST peut croître linéairement avec le nombre de nœuds, et donc que le temps de requête est proportionnel à la taille du jeu de données.

Preuve que les arbres AVL ont une hauteur logarithmique

Considérons le nombre minimal de nœuds, M(h), requis pour créer un arbre AVL de hauteur h. Comme il s’agit d’un arbre AVL, il est important de noter que le facteur d’équilibre de chaque nœud ne peut être que -1, 0 ou 1.

Cependant, étant donné notre hypothèse que l’arbre contient le minimum de nœuds pour atteindre la hauteur h, la racine ne peut pas avoir un équilibre de 0. Sinon, on pourrait retirer un nœud à gauche ou à droite pour obtenir un équilibre de -1 ou 1 et conserver un arbre AVL valide.

Supposons que l’équilibre de la racine soit 1 (le raisonnement est identique pour -1). Cela implique que l’arbre est structuré comme suit :

Structure d’un arbre AVL de hauteur h avec nombre minimal de nœuds

Par ailleurs, les sous-arbres gauche et droit doivent aussi être des arbres AVL, chacun avec le nombre minimal de nœuds pour leurs hauteurs respectives (sinon, on pourrait retirer des nœuds supplémentaires). Le nombre total de nœuds est égal à 1 (pour la racine) plus le nombre de nœuds dans le sous-arbre gauche, plus celui du sous-arbre droit.

M(h) = 1 + (nœuds dans L) + (nœuds dans R) = 1 + M(h - 1) + M(h - 2)

À mesure que la hauteur augmente, il faut ajouter plus de nœuds pour l’atteindre. Donc :

M(h - 1) > M(h - 2)

En combinant les deux, on obtient :

M(h) = 1 + M(h - 1) + M(h - 2) > 1 + 2 × M(h - 2) > 2 × M(h - 2)

Nous pouvons appliquer cela h/2 fois jusqu’à atteindre M(1) = 1 ou M(2) = 2 :

M(h) > 2 × M(h - 2) > 2 × 2 × M(h - 4) > 2 × 2 × 2 × M(h - 6) > … > 2(h/2)

Pour plus de clarté, l’image suivante montre les cas spécifiques h = 7 et h = 6 :

Calcul de M(h) pour h = 7 et h = 6

Nous concluons que le nombre minimal de nœuds dans un arbre AVL de hauteur h est au moins 2(h/2) :

M(h) > 2(h/2)

En appliquant le logarithme en base deux des deux côtés, on obtient :

log2(M(h)) > log2(2(h/2)) = h/2

Par conséquent, en multipliant les deux côtés par deux, on déduit que la hauteur est au plus deux fois le logarithme en base 2 du nombre de nœuds :

2 × log2(M(h)) > h

Nous avons montré que :

La hauteur d’un arbre AVL contenant N nœuds est au plus 2 × log2(N).

Cela signifie que les requêtes dans un arbre AVL n’exigent d’examiner qu’une petite partie du jeu de données. Par exemple, pour un milliard d’entrées, le logarithme vaut environ 30 : même avec un milliard de points de données, il suffit d’en examiner environ 60 pour trouver une entrée spécifique. C’est un gain considérable par rapport aux BST qui, dans le pire des cas, imposeraient d’inspecter le milliard complet de points.

Pour approfondir la complexité temporelle des algorithmes et la différence entre complexité linéaire et logarithmique, consultez cet article de blog sur la notation Big-O et la complexité temporelle.

Maintenir l’équilibre avec les arbres AVL

Les arbres AVL garantissent des requêtes rapides en imposant que l’équilibre de chaque nœud soit -1, 0 ou 1. Pour maintenir cet équilibre, il faut rééquilibrer l’arbre après chaque insertion d’une nouvelle valeur.

L’insertion dans un arbre binaire de recherche suit le chemin depuis la racine vers le bas : on va à gauche quand la valeur à insérer est plus petite, sinon à droite.

Insertion d’une valeur dans un BST

Une insertion augmente la hauteur d’au plus un. Donc, si la propriété d’équilibre n’est pas respectée après insertion, c’est qu’un nœud avec un équilibre -1 est passé à -2, ou qu’un nœud avec un équilibre 1 est passé à 2. Le premier cas se produit dans l’exemple ci-dessus.

Facteurs d’équilibre après insertion

Rotations simples

Pour rétablir l’équilibre, on s’appuie sur des rotations. Une rotation gauche sur le nœud A réorganise l’arbre en faisant pivoter A vers la gauche, comme ci-dessous :

Rotation gauche dans les arbres AVL

Sur le schéma :

  • BL représente le sous-arbre gauche de B
  • BR est le sous-arbre droit
  • AL est le sous-arbre gauche de A

Notez qu’après rotation, l’ordre des nœuds reste valide :

  1. Le nœud A est plus petit que B car B était son enfant droit.
  2. Les nœuds de BL sont supérieurs à A car ils étaient à droite de A.
  3. Les nœuds de AL sont inférieurs à B puisqu’ils sont inférieurs à A.

Une rotation droite fonctionne de manière symétrique en faisant pivoter A vers la droite.

Rotations droites dans les arbres AVL

Voyons un exemple concret en corrigeant le déséquilibre apparu après l’insertion de 19 via une rotation gauche sur le nœud 6.

Exemple de rotation gauche

Après l’insertion, nous corrigeons le déséquilibre en faisant pivoter un nœud dont l’équilibre vaut -2 ou 2. Ici, le facteur d’équilibre du nœud 6 était -2 : l’arbre penchait à droite, nous avons donc appliqué une rotation gauche (dans le sens opposé au déséquilibre). Si l’équilibre vaut 2, on applique une rotation droite.

Rotations doubles

Dans l’exemple précédent, l’arbre penchait totalement à droite, donc une seule rotation gauche suffisait. Mais il existe des déséquilibres en zigzag : l’arbre penche d’un côté, mais le sous-arbre penche de l’autre. Pour l’illustrer, revenons à l’arbre initial, avant l’insertion de 19, et insérons 7 à la place :

Exemple d’insertion en zigzag dans un BST

Ici, l’arbre penche toujours à droite, mais le sous-arbre enraciné en 10 penche à gauche. On commence donc par faire une rotation droite sur le nœud 10 :

Exemple de rotation droite dans un arbre AVL

Notez que le nœud B n’a pas d’enfant droit. Nous le laissons en bleu dans le schéma pour faciliter la visualisation.

Après la rotation droite, on retombe dans le cas précédent : une rotation gauche sur 6 rétablit l’équilibre :

Exemple de rotation double

Comment implémenter un arbre AVL en Python

Commençons par l’implémentation d’un nœud.

Implémentation du nœud

Chaque nœud de l’arbre possède cinq attributs :

  • La valeur stockée (self.value)
  • Le nœud parent (self.parent)
  • L’enfant gauche (self.left)
  • L’enfant droit (self.right)
  • La hauteur du sous-arbre enraciné à ce nœud (self.height)
class Node:
  def __init__(self, value, parent = None):
    self.value = value
    self.parent = parent
    self.left = None
    self.right = None
    self.height = 1

Nous utilisons la valeur None pour représenter les nœuds manquants. La height par défaut est fixée à 1, car un arbre réduit à un seul nœud a une hauteur de 1.

Pour faciliter l’implémentation de l’arbre, nous ajoutons plusieurs méthodes à la classe Node.

# Inside the Node class
  def left_height(self):
    # Get the heigth of the left subtree
    return 0 if self.left is None else self.left.height
  
  def right_height(self):
    # Get the height of the right subtree
    return 0 if self.right is None else self.right.height
  def balance_factor(self):
    # Get the balance factor
    return self.left_height() - self.right_height()
  def update_heigth(self):
    # Update the heigth of this node
    self.height = 1 + max(self.left_height(),self.right_height())
    
  def set_left(self, node):
    # Set the left child
    self.left = node
    if node is not None:
      node.parent = self
    self.update_heigth()
  
  def set_right(self, node):
    # Set the right child
    self.right = node
    if node is not None:
      node.parent = self
    self.update_heigth()
  def is_left_child(self):
    # Check whether this node is a left child
    return self.parent is not None and self.parent.left == self
  
  def is_right_child(self):
    # Check whether this node is a right child
    return self.parent is not None and self.parent.right == self

Notez que nous utilisons les méthodes .set_left() et .set_right() pour affecter respectivement les enfants gauche et droit. Plutôt que de modifier directement self.left et self.right, ces méthodes garantissent qu’à chaque changement d’enfant, le parent du nouvel enfant est mis à jour ainsi que la hauteur du nœud.

Implémentation de l’arbre AVL

L’arbre AVL maintient un paramètre : la racine de l’arbre, c’est-à-dire son nœud supérieur.

class AVLTree:
  def __init__(self):
    self.root = None

Pour maintenir l’équilibre, nous devons implémenter les rotations gauche et droite. Rappelons comment une rotation gauche est illustrée sur le schéma :

Rotation gauche sur un arbre AVL

# Inside the AVLTree class
  
  def rotate_left(self, a):
    b = a.right
    # 1. The new right child of A becomes the left child of B
    a.set_right(b.left)
    # 2. The new left child of B becomes A
    b.set_left(a)
    return b # 3. Return B to replace A with it

Les rotations droites s’implémentent de façon symétrique :

# Inside the AVLTree class
  
  def rotate_right(self, a):
    b = a.left
    a.set_left(b.right)
    b.set_right(a)
    return b

À l’aide des rotations, nous pouvons rééquilibrer l’arbre. Un nœud nécessite un rééquilibrage lorsque son facteur d’équilibre atteint 2 (l’arbre penche à gauche) ou -2 (l’arbre penche à droite). Au total, quatre cas sont à considérer :

Les quatre cas de rotation pour les arbres AVL

Nous implémentons ces quatre cas dans la méthode .rebalance().

# Inside the AVLTree class
  
  def rebalance(self, node):
    if node is None:
      # Empty tree, no rebalancing needed
      return None
    balance = node.balance_factor()
    if abs(balance) <= 1:
      # The node is already balanced, no rebalancing needed
      return node
    if balance == 2: 
      # Cases 1 and 2, the tree is leaning to the left
      if node.left.balance_factor() == -1: 
        # Case 2, we first do a left rotation
        node.set_left(self.rotate_left(node.left))
      return self.rotate_right(node)
    # Balance must be -2
    # Cases 3 and 4, the tree is leaning to the left
    if node.right.balance_factor() == 1:
      # Case 4, we first do a right rotation
      node.set_right(self.rotate_right(node.right)) 
    return self.rotate_left(node)

Remarquez que chaque cas renvoie la racine du sous-arbre qui vient d’être équilibré. Cette nouvelle racine sera utilisée ensuite pour mettre à jour les enfants pendant le processus de rééquilibrage.

L’ajout d’un nœud à un arbre AVL ressemble à celui d’un BST, avec en plus la restauration de l’équilibre après insertion. Pour ajouter un nœud dans un BST, on part de la racine et on descend dans l’arbre. À chaque étape, on compare la valeur à ajouter à celle du nœud courant : si elle est plus petite, on va à gauche ; sinon, à droite. En descendant, on mémorise le parent pour insérer le nouveau nœud comme enfant.

Une fois un emplacement vide atteint, deux cas se présentent :

  1. Le parent est None : l’arbre est vide, le nouveau nœud devient la racine.
  2. On a trouvé le parent : on affecte le nouveau nœud à gauche ou à droite selon les valeurs.
# Inside the AVLTree class
  def add(self, value):
    self.size += 1
    parent = None
    current = self.root
    while current is not None:
      parent = current
      if value < current.value:
        # Value to insert is smaller than node value, go left
        current = current.left
      else:
        # Value to insert is larger than node value, go right
        current = current.right
    # We found the parent, create the new node
    new_node = Node(value, parent)
    # Case 1: The parent is None so the new node is the root
    if parent is None:
      self.root = new_node
    else:
      # Case 2: Set the new node as a child of the parent
      if value < parent.value:
        parent.left = new_node
      else:
        parent.right = new_node
    # After a new node is added, we need to restore balance
    self.restore_balance(new_node)

La seule différence entre la méthode .add() d’un BST et celle d’un arbre AVL tient à l’étape finale : remonter l’arbre depuis le nœud ajouté jusqu’à la racine et rééquilibrer chaque nœud grâce à .rebalance().

# Inside the AVLTree class
  def restore_balance(self, node):
    current = node
    # Go up the tree and rebalance left and right children
    while current is not None:
      current.set_left(self.rebalance(current.left))
      current.set_right(self.rebalance(current.right))
      current.update_heigth()
      current = current.parent
    self.root = self.rebalance(self.root)
    self.root.parent = None

Notez que .rebalance() ne fait rien si le nœud est déjà équilibré : elle renvoie simplement ce nœud. C’est pourquoi, en remontant l’arbre, on peut l’appeler des deux côtés, même si un seul peut être déséquilibré. L’autre appel ne change rien.

Rappelons que nous avons conçu .rebalance() pour qu’elle renvoie la (potentielle) nouvelle racine du sous-arbre. Ainsi, en remontant, nous pouvons mettre à jour les enfants gauche et droit des nœuds courants tout en restaurant l’équilibre.

Le schéma suivant illustre les étapes de .restore_balance() en remontant l’arbre.

Restauration de l’équilibre d’un arbre AVL

Dans l’exemple, nous ajoutons d’abord le nœud 8. Le processus de restauration commence alors à ce nœud et remonte l’arbre, en vérifiant et rééquilibrant les enfants gauche et droit de chaque nœud rencontré, jusqu’au nœud 10. Jusqu’à ce point, les appels à .rebalance() n’ont aucun effet, les nœuds restant équilibrés.

En revanche, au niveau du nœud 10, on constate que son enfant gauche, le nœud 7, a un facteur d’équilibre de -2 : un rééquilibrage est nécessaire. L’appel .rebalance(7) remplace alors l’enfant gauche de 10 par la nouvelle racine du sous-arbre gauche, le nœud 8, restaurant l’équilibre.

Opérations supplémentaires sur les arbres AVL

Outre l’ajout et la suppression tout en conservant l’équilibre, les arbres AVL prennent en charge d’autres opérations essentielles.

Minimum et maximum

Grâce à l’ordre des BST, la valeur minimale se trouve au nœud le plus à gauche de l’arbre, et la valeur maximale au nœud le plus à droite.

Valeurs minimale et maximale dans un arbre AVL

Nous avons implémenté deux fonctions utilitaires qui identifient les nœuds extrêmes gauche et droit à partir d’un nœud donné. Elles facilitent notamment la suppression de nœuds.

# Inside the AVLTree class
  
  def leftmost(self, starting_node):
    # Find the leftmost node from a given starting node
    previous = None
    current = starting_node
    while current is not None:
      previous = current
      current = current.left
    return previous
  def minimum(self):
    # Return the minimum value in the tree
    if self.root is None:
      raise Exception("Empty tree")
    return self.leftmost(self.root).value
# Inside the AVLTree class
 
  def rightmost(self, starting_node):
    # Find the rightmost node from a given starting node
    previous = None
    current = starting_node
    while current is not None:
      previous = current
      current = current.right
    return previous
  
  def maximum(self):
    # Fidn the maximum value in the tree
    if self.root is None:
      raise Exception("Empty tree")
    return self.rightmost(self.root).value

Contains

Pour savoir si un arbre contient une valeur donnée, on s’appuie sur la propriété d’ordre : depuis la racine, on part à gauche si la valeur recherchée est inférieure au nœud courant, sinon à droite. Si l’on atteint la fin de l’arbre sans trouver la valeur, c’est qu’elle n’y figure pas.

Pour cela, nous implémentons une méthode utilitaire .locate_node(), utile pour la recherche mais aussi pour la suppression. Nous utilisons également la méthode .__contains__() qui permet d’employer l’opérateur in pour vérifier simplement la présence d’une valeur dans l’arbre.

# Inside the AVLTree class

  def locate_node(self, value):

    # Returns the node containing a given value or None if no

    # such node exists

    current = self.root

    while current is not None:

      if value == current.value:

        return current

      if value < current.value:

        current = current.left

      else:

        current = current.right

    return None

  def __contains__(self, value):

    node = self.locate_node(value)

    return node is not None

Suppression

Supprimer un nœud dans un arbre AVL peut être délicat lorsqu’il se situe au milieu de l’arbre. S’il s’agit d’une feuille, c’est-à-dire sans enfant, on peut simplement le supprimer en mettant à None le pointeur enfant gauche ou droit de son parent selon le cas.

Cas particulier : si le nœud à supprimer est la racine, on peut l’enlever en définissant la racine à None.

# Inside the AVLTree class

  def delete_leaf(self, node):

    if node.parent is None:

      self.root = None

    elif node.is_left_child():

      node.parent.left = None

      node.parent = None

    else:

      node.parent.right = None

      node.parent = None

Pour supprimer une valeur d’un arbre AVL, on commence par localiser le nœud qui la contient via .locate_node(). Si c’est une feuille, on le retire avec .delete_leaf(). Sinon, une suppression directe casserait la structure : il faut trouver un nœud de remplacement. Si le nœud à supprimer a un enfant gauche, on choisit le nœud le plus à droite de son sous-arbre gauche. Cette approche préserve l’ordre de l’arbre.

Le schéma ci-dessous illustre la suppression du nœud 10. Comme il a un enfant gauche, on le remplace par le nœud le plus à droite du sous-arbre gauche. Après remplacement, il est crucial de rééquilibrer l’arbre en partant du parent du nœud remplacé.

Suppression de nœuds dans un arbre AVL

Dans cet exemple, le nœud de remplacement est une feuille. Mais s’il a des enfants, il faut les rattacher au parent du nœud de remplacement. Comme ce nœud est extrême (le plus à gauche ou à droite), il ne peut avoir qu’un seul enfant : ce rattachement est donc toujours possible.

Rattachement des nœuds dans un arbre AVL

# Inside the AVLTree class

  def delete(self, value):

    # Delete a value from the tree

    node = self.locate_node(value)

    if node is None:

      raise Exception("Value not stored in tree")

    replacement = None

    rebalance_node = node.parent

    if node.left is not None:

      # There's a left child so we replace with rightmost node

      replacement = self.rightmost(node.left)

      # Check if reparenting is needed

      if replacement.is_left_child():

        replacement.parent.set_left(replacement.left)

      else:

        replacement.parent.set_right(replacement.left)

    elif node.right is not None:

      # There's a right child so we replace with the leftmost node

      replacement = self.leftmost(node.right)

      # Check if reparenting is needed

      if replacement.is_left_child():

        replacement.parent.set_left(replacement.right)

      else:

        replacement.parent.set_right(replacement.right)

    if replacement:

      # We found a replacement so replace the value

      node.value = replacement.value

      rebalance_node = replacement.parent

    else:

      # No replacement so it means the node to delete is a leaf

      self.delete_leaf(node)

    if rebalance_node is not None:

      self.restore_balance(rebalance_node)

Requête de plage

Les requêtes de plage consistent à identifier toutes les valeurs comprises entre deux bornes. Grâce à l’ordre des arbres AVL, on peut les localiser efficacement.

Requêtes de plage dans un arbre AVL

Pour trouver toutes les valeurs comprises entre la borne inférieure lb et la borne supérieure ub, nous parcourons récursivement l’arbre. Pour chaque nœud dont la valeur est dans l’intervalle, nous l’ajoutons aux résultats, puis explorons ses sous-arbres gauche et droit.

On ignore le sous-arbre gauche si la valeur du nœud est inférieure à la borne inférieure, car toutes les valeurs du sous-arbre gauche sont plus petites que celle du nœud. De même, on ignore le sous-arbre droit si la valeur du nœud est supérieure à la borne supérieure, car toutes ses valeurs seront plus grandes.

  def search(self, node, lb, ub, results):

    # Search for values between lower bound and upper bound

    if node is None:

      return

    if lb <= node.value and node.value <= ub:

      results.append(node.value)

    if node.value >= lb:

      self.search(node.left, lb, ub, results)

    if node.value <= ub:

      self.search(node.right, lb, ub, results)

  def range_query(self, lb, ub):

    # Search for values between lower bound and upper bound

    results = []

    self.search(self.root, lb, ub, results)

    return results

Autres arbres auto-équilibrés

Nous avons implémenté un arbre AVL capable d’exécuter les opérations suivantes :

  • Ajout d’une valeur
  • Suppression d’une valeur
  • Recherche d’une valeur
  • Interrogation des minimum et maximum
  • Interrogation de toutes les valeurs entre deux bornes

Le package avltree propose une implémentation Python reflétant ces capacités.

D’autres arbres binaires de recherche auto-équilibrés, tels que les arbres rouge-noir, les splay trees et les B-arbres, offrent des fonctionnalités similaires. En général, leurs performances sont comparables dans la plupart des applications, car ils conservent tous une hauteur logarithmique garantie. Les arbres AVL sont toutefois plus finement équilibrés : ils optimisent la recherche au prix d’insertions parfois plus lentes à cause d’un rééquilibrage plus strict.

Les splay trees sont particulièrement efficaces lorsque les éléments récemment consultés sont souvent réutilisés ; ils sont donc très adaptés aux mécanismes de cache.

Les B-arbres sont conçus pour fonctionner efficacement sur disque plutôt qu’en mémoire. Ils sont précieux pour gérer de très grands volumes de données dépassant la mémoire, comme pour la création d’index de bases de données.

Pistes d’amélioration

Plusieurs améliorations sont possibles. Voici quelques idées d’exercices pour approfondir votre compréhension des arbres AVL :

  • Dans notre implémentation, les nœuds stockent une seule valeur. Pour un usage en index de base de données, il faut stocker des lignes entières, car la valeur correspond à une colonne. On peut enrichir l’implémentation pour faire fonctionner l’arbre AVL comme un dictionnaire, liant les valeurs à leurs lignes.
  • Notre implémentation ne gère pas les doublons. On peut la modifier pour autoriser plusieurs nœuds partageant la même valeur.
  • Classiquement, les arbres AVL sont implémentés de façon récursive. Nous avons choisi l’itératif pour éviter d’exiger une forte maîtrise de la récursion. Les versions récursives sont souvent plus élégantes et concises, mais nécessitent une compréhension solide du concept.

Conclusion

Les BST sont un type d’arbre binaire qui organise les données selon un ordre précis. Cette organisation évite d’inspecter l’ensemble du jeu de données lors des recherches. Cependant, ils peuvent se déséquilibrer et dégrader les performances, pouvant aller jusqu’à exiger l’inspection complète du jeu de données.

Les arbres AVL résolvent ce problème en imposant des propriétés d’équilibre via des rotations. Ces propriétés garantissent une hauteur logarithmique par rapport à la taille des données, ce qui améliore nettement les performances.

Une complexité logarithmique représente un progrès majeur par rapport à une complexité linéaire : les arbres AVL sont donc très efficaces pour les requêtes. Même avec des milliards d’entrées, ils ne nécessitent d’inspecter que très peu de points de données pour trouver un élément.

Devenez ingénieur en données

Faites la preuve de vos compétences en tant qu'ingénieur en données prêt à l'emploi.

François Aubry's photo
Author
François Aubry
LinkedIn
Ingénieur full-stack et fondateur de CheapGPT. L'enseignement a toujours été ma passion. Dès mes premiers jours d'études, j'ai cherché avec enthousiasme des occasions de donner des cours particuliers et d'aider d'autres étudiants. Cette passion m'a amenée à poursuivre un doctorat, où j'ai également été assistante d'enseignement pour soutenir mes efforts académiques. Au cours de ces années, j'ai trouvé un immense épanouissement dans le cadre d'une classe traditionnelle, en favorisant les liens et en facilitant l'apprentissage. Cependant, avec l'avènement des plateformes d'apprentissage en ligne, j'ai reconnu le potentiel de transformation de l'éducation numérique. En fait, j'ai participé activement au développement d'une telle plateforme dans notre université. Je suis profondément engagée dans l'intégration des principes d'enseignement traditionnels avec des méthodologies numériques innovantes. Ma passion est de créer des cours qui sont non seulement attrayants et instructifs, mais aussi accessibles aux apprenants à l'ère du numérique.
Sujets
Ingénierie des données

Apprenez le data engineering avec ces cours !

Cursus

Ingénieur de données en Python

40 h
Acquérir des compétences très demandées pour ingérer, nettoyer et gérer efficacement les données, ainsi que pour planifier et surveiller les pipelines, vous permettra de vous démarquer dans le domaine de l'ingénierie des données.
Afficher les détailsRight Arrow
Commencer Le Cours
Voir plusRight Arrow