---
title: "Arbres AVL"
date: "2023-03-31"
---

# Questions sur les notions du dernier cours

* Qu'est-ce qu'un arbre AVL?

. . .

* Un arbre binaire qui a la propriété suivante:
    * La différence de hauteur de chaque noeud est d'au plus 1.
    * Tous les noeuds ont `fe = hd - hg = {-1, 0, 1}`.

* Pourquoi utiliser un arbre AVL plutôt qu'un arbre binaire de recherche?

. . .

* Insertion/recherche/... toujours en $O(\log_2(N))$.

# AVL ou pas?

\footnotesize

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((21))-->id1((9));
    id0-->id2((40));
    id1-->id3((5));
    id1-->id4((10));
    id3-->id5((3));
    id3-->id6((7))
    id6-->id7((6))
    id6-->id8((  ))
    id2-->id9((33))
    id2-->id10((61))
    id9-->id11((22))
    id9-->id12((39))
    id10-->id13((  ))
    id10-->id14((81))
    style id8 fill:#fff,stroke:#fff
    style id13 fill:#fff,stroke:#fff
```

. . .

* Ajouter un noeud pour qu'il le soit plus.

# Insertion dans un arbre AVL

\footnotesize

1. On part d'un arbre AVL.
2. On insère un nouvel élément.

::: columns

:::: column

* `hd ? hg`.
* Insertion de `4`?

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id1-->id3((  ));
    id1-->id4((6));
    id2-->id5((  ));
    id2-->id6((  ));
    style id3 fill:#fff,stroke:#fff
    style id5 fill:#fff,stroke:#fff
    style id6 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

* `hd > hg`

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((12))-->id1((1));
    id0-->id2((19));
    id1-->id3((  ));
    id1-->id4((6));
    id4-->id5((4));
    id4-->id6((  ));
    id2-->id7((  ));
    id2-->id8((  ));
    style id3 fill:#fff,stroke:#fff
    style id6 fill:#fff,stroke:#fff
    style id7 fill:#fff,stroke:#fff
    style id8 fill:#fff,stroke:#fff
```

::::

:::

**Déséquilibre!** Que vaut `fe`?

. . .

* `fe = 2`

# Les cas de déséquilibre


::: columns

:::: column

## Cas 1a

* `u`, `v`, `w` même hauteur.
* déséquilibre en `B` après insertion dans `u`

![Après insertion](figs/cas1a_gauche.png)

::::

:::: column

## Cas 1a

* Comment rééquilibrer?

. . .

* ramène `u`, `v` `w` à la même hauteur.
* `v` à droite de `A` (gauche de `B`)

![Après équilibrage](figs/cas1a_droite.png)

::::

:::

# Les cas de déséquilibre


::: columns

:::: column

## Cas 1b (symétrique 1a)

![Après insertion](figs/cas1b_gauche.png)

::::

:::: column

## Cas 1b (symétrique 1a)

* Comment rééquilibrer?

. . .

![Après équilibrage](figs/cas1b_droite.png)

::::

:::

# Les cas de déséquilibre


::: columns

:::: column

## Cas 2a

* `h(v1)=h(v2), h(u)=h(w)`.
* déséquilibre en `C` après insertion dans `v2`

![Après insertion](figs/cas2a_gauche.png)

::::

:::: column

## Cas 2a

* Comment rééquilibrer?

. . .

* ramène `u`, `v2`, `w` à la même hauteur (`v1` pas tout à fait).
* `v2` à droite de `B` (gauche de `C`)
* `B` à droite de `A` (gauche de `C`)
* `v1` à droite de `A` (gauche de `B`)

![Après équilibrage](figs/cas2a_droite.png)

::::

:::


# Les cas de déséquilibre


::: columns

:::: column

## Cas 2b (symétrique 2a)

![Après insertion](figs/cas2b_gauche.png)

::::

:::: column

## Cas 2b (symétrique 2a)

* Comment rééquilibrer?

. . .

![Après équilibrage](figs/cas2b_droite.png)

::::

:::

# Le facteur d'équilibre (balance factor)

## Définition

```
fe(arbre) = hauteur(droite(arbre)) - hauteur(gauche(arbre))
```

## Valeurs possibles?

. . .

```
fe = {-1, 0, 1} // arbre AVL
fe = {-2, 2}    // arbre déséquilibré
```

![Illustration du `fe`](figs/facteur_equilibre.png){width=40%}

# Algorithme d'insertion

* Insérer le noeud comme d'habitude.
* Mettre à jour les facteurs d'équilibre jusqu'à la racine (ou au premier
  noeud déséquilibré).
* Rééquilibrer le noeud si nécessaire.

## Cas possibles

::: columns

:::: column

## Sous-arbre gauche (avant)

```
fe(P) =  1 
fe(P) =  0 
fe(P) = -1 
```

::::

:::: column

## Sous-arbre gauche (après)

. . .

```
=> fe(P) =  0 
=> fe(P) = -1 
=> fe(P) = -2 // Rééquilibrer P
```

::::

:::

# Algorithme d'insertion

* Insérer le noeud comme d'habitude.
* Mettre à jour les facteurs d'équilibre jusqu'à la racine (ou au premier
  noeud déséquilibré).
* Rééquilibrer le noeud si nécessaire.

## Cas possibles

::: columns

:::: column

## Sous-arbre droit (avant)

```
fe(P) =  1 
fe(P) =  0 
fe(P) = -1 
```

::::

:::: column

## Sous-arbre droit (après)

. . .

```
=> fe(P) =  0 
=> fe(P) = +1 
=> fe(P) = +2 // Rééquilibrer P
```

::::

:::

# Rééquilibrage

## Lien avec les cas vus plus tôt

```
fe(P) = -2 && fe(gauche(P)) = -1 => cas 1a
fe(P) = -2 && fe(gauche(P)) = +1 => cas 2a

fe(P) = +2 && fe(droite(P)) = -1 => cas 2b
fe(P) = +2 && fe(droite(P)) = +1 => cas 1b
```

## Dessiner les différents cas, sur le dessin ci-dessous

![On verra un peu après les rotations.](figs/rotation_gauche_droite.png)

# La rotation

## La rotation gauche (5min, matrix)

![L'arbre de droite devient celui de gauche. Comment?](figs/rotation_gauche_droite.png)

. . .

\footnotesize
```
arbre rotation_gauche(arbre P) 
    si est_non_vide(P)
        Q = droite(P)
        droite(P) = gauche(Q)
        gauche(Q) = P
        retourne Q
    retourne P
```

# La rotation en C (1/2)

## La rotation gauche

```
arbre rotation_gauche(arbre P) 
    si est_non_vide(P)
        Q = droite(P)
        droite(P) = gauche(Q)
        gauche(Q) = P
        retourne Q
    retourne P
```

## Écrire le code C correspondant (5min, matrix)

1. Structure de données
2. Fonction `tree_t rotation_left(tree_t tree)`

. . .

\footnotesize
```C
typedef struct _node {
    int key;
    struct _node *left, *right;
    int bf; // balance factor
} node;
typedef node *tree_t;
```

# La rotation en C (2/2)

\footnotesize

```C
tree_t rotation_left(tree_t tree) {
    tree_t subtree = NULL;
    if (NULL != tree) {
        subtree = tree->right;
        tree->right = subtree->left;
        subtree->left = tree;
    }
    return subtree;
}
```

. . .

* Et la rotation à droite, pseudo-code (5min)?

. . .

```
arbre rotation_droite(arbre P) 
    si est_non_vide(P)
        Q = gauche(P)
        gauche(P) = droite(Q)
        droite(Q) = P
        retourne Q
    retourne P
```

<!-- ```C
tree_t rotation_right(tree_t tree) {
    tree_t subtree = NULL;
    if (NULL != tree) {
        subtree = tree->left;
        tree->left = subtree->right;
        subtree->right = tree;
    }
    return subtree;
}
``` -->

# Exemple de rotation (1/2)

## Insertion de 9?

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((5))-->id1((1));
    id0-->id2((6));
    id2-->id3((  ));
    id2-->id4((8));
    style id3 fill:#fff,stroke:#fff
```

# Exemple de rotation (2/2)

::: columns

:::: column

## Quelle rotation et sur quel noeud (5 ou 6)?

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((5))-->id1((1));
    id0-->id2((6));
    id2-->id3((  ));
    id2-->id4((8));
    id4-->id5((  ));
    id4-->id6((9));
    style id3 fill:#fff,stroke:#fff
    style id5 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

## Sur le plus jeune évidemment!

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((5))-->id1((1));
    id0-->id2((8));
    id2-->id3((6));
    id2-->id4((9));
```

::::

:::

* Cas `1a/b` *check*!


# La rotation gauche-droite

## Là c'est plus difficile (cas 2a/b)

![La double rotation de l'enfer.](figs/double_rotation_gauche_droite.png)

# Exercices

## Faire l'implémentation de la double rotation (pas corrigé, 5min)

# Exercices

::: columns

:::: column

## Insérer 50, ex 10min (matrix)

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((89))-->id1((71));
    id0-->id2((90));
    id1-->id3((44));
    id3-->id4((37));
    id3-->id5((61));
    id1-->id6((81))
    id2-->id7((  ))
    id2-->id8((100))
    style id7 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

## Où se fait la rotation?

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((89))-->id1((71));
    id0-->id2((90));
    id1-->id3((44));
    id3-->id4((37));
    id3-->id5((61));
    id1-->id6((81))
    id2-->id7((  ))
    id2-->id8((100))
    id5-->id9((50))
    id5-->id10((  ))
    style id7 fill:#fff,stroke:#fff
    style id10 fill:#fff,stroke:#fff
```

::::

:::

# Exercices

::: columns

:::: column

## Rotation gauche en 44

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((89))-->id1((71));
    id0-->id2((90));
    id1-->id3((61));
    id1-->id10((81));
    id3-->id4((44));
    id3-->id5((  ));
    id4-->id6((37))
    id4-->id7((50))
    id2-->id8((  ))
    id2-->id9((100))
    style id5 fill:#fff,stroke:#fff
    style id8 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

## Rotation à droite en 71

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((89))-->id1((61));
    id0-->id2((90));
    id1-->id3((44));
    id1-->id10((71));
    id3-->id4((37));
    id3-->id5((50));
    id2-->id8((  ));
    id2-->id9((100));
    id10-->id11((  ))
    id10-->id12((81))
    style id8 fill:#fff,stroke:#fff
    style id11 fill:#fff,stroke:#fff
```

::::

:::

# Exercice de la mort

Soit l’arbre AVL suivant:

::: columns

:::: column

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((60))-->id1((40));
    id0-->id2((120));
    id1-->id3((20));
    id1-->id4((50));
    id3-->id5((10));
    id3-->id6((30));
    id2-->id7((100));
    id2-->id8((140));
    id7-->id9((80))
    id7-->id10((110))
    id9-->id11((70))
    id9-->id12((90))
    id8-->id13((130))
    id8-->id14((160))
    id14-->id15((150))
    id14-->id16((170))
```

::::

:::: column

1. Montrer les positions des insertions de feuille qui conduiront à un arbre
   désequilibré.
2. Donner les facteurs d’equilgaucheibre.
3. Dessiner et expliquer les modifications de l’arbre lors de l’insertion de la
   valeur `65`. On mentionnera les modifications des facteurs
   d’équilibre.

::::

:::

# Encore un petit exercice

* Insérer les nœuds suivants dans un arbre AVL

```
25 | 60 | 35 | 10 | 5 | 20 | 65 | 45 | 70 | 40 
    | 50 | 55 | 30 | 15
```

## Un à un et le/la premier/ère qui poste la bonne réponse sur matrix a un point

# Suppression dans un arbre AVL


::: columns

:::: column

## Algorithme par problème: supprimer 10

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((8))-->id1((4));
    id0-->id2((10));
    id1-->id3((2));
    id1-->id4((6));
    id3-->id5((1));
    id3-->id6((  ))
    id4-->id7((  ))
    id4-->id8((7))
    id2-->id9((9))
    id2-->id10((14))
    id10-->id11((12))
    id10-->id12((16))
    style id6 fill:#fff,stroke:#fff
    style id7 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

## Algorithme par problème: supprimer 10

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((8))-->id1((4));
    id0-->id2((12));
    id1-->id3((2));
    id1-->id4((6));
    id3-->id5((1));
    id3-->id6((  ))
    id4-->id7((  ))
    id4-->id8((7))
    id2-->id9((9))
    id2-->id10((14))
    id10-->id11((  ))
    id10-->id12((16))
    style id6 fill:#fff,stroke:#fff
    style id7 fill:#fff,stroke:#fff
    style id11 fill:#fff,stroke:#fff
```

::::

:::

# Suppression dans un arbre AVL


::: columns

:::: column

## Algorithme par problème: supprimer 8

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((8))-->id1((4));
    id0-->id2((12));
    id1-->id3((2));
    id1-->id4((6));
    id3-->id5((1));
    id3-->id6((  ))
    id4-->id7((  ))
    id4-->id8((7))
    id2-->id9((9))
    id2-->id10((14))
    id10-->id11((  ))
    id10-->id12((16))
    style id6 fill:#fff,stroke:#fff
    style id7 fill:#fff,stroke:#fff
    style id11 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

## Algorithme par problème: rotation de 12

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((9))-->id1((4));
    id0-->id2((12));
    id1-->id3((2));
    id1-->id4((6));
    id3-->id5((1));
    id3-->id6((  ))
    id4-->id7((  ))
    id4-->id8((7))
    id2-->id9((  ))
    id2-->id10((14))
    id10-->id11((  ))
    id10-->id12((16))
    style id6 fill:#fff,stroke:#fff
    style id7 fill:#fff,stroke:#fff
    style id9 fill:#fff,stroke:#fff
    style id11 fill:#fff,stroke:#fff
```

::::

:::

# Suppression dans un arbre AVL

::: columns

:::: column

## Algorithme par problème: rotation de 12

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((9))-->id1((4));
    id0-->id2((14));
    id1-->id3((2));
    id1-->id4((6));
    id3-->id5((1));
    id3-->id6((  ))
    id4-->id7((  ))
    id4-->id8((7))
    id2-->id9((12))
    id2-->id10((16))
    style id6 fill:#fff,stroke:#fff
    style id7 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

1. On supprime comme d'habitude.
2. On rééquilibre si besoin à l'endroit de la suppression.

* Facile non?

. . .

* Plus dur....

::::

:::

# Suppression dans un arbre AVL 2.0

::: columns

:::: column

## Algorithme par problème: suppression de 30

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((50))-->id1((30));
    id0-->id2((100));
    id1-->id3((10));
    id1-->id4((40));
    id3-->id5((  ));
    id3-->id6((20))
    id2-->id7((80))
    id2-->id8((200))
    id7-->id9((70))
    id7-->id10((90))
    id9-->id11((60))
    id9-->id12((  ))
    id8-->id13((  ))
    id8-->id14((300))
    style id5 fill:#fff,stroke:#fff
    style id12 fill:#fff,stroke:#fff
    style id13 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

## Algorithme par problème: rotation GD autour de 40

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((50))-->id1((40));
    id0-->id2((100));
    id1-->id3((10));
    id1-->id4((  ));
    id3-->id5((  ));
    id3-->id6((20))
    id2-->id7((80))
    id2-->id8((200))
    id7-->id9((70))
    id7-->id10((90))
    id9-->id11((60))
    id9-->id12((  ))
    id8-->id13((  ))
    id8-->id14((300))
    style id4 fill:#fff,stroke:#fff
    style id5 fill:#fff,stroke:#fff
    style id12 fill:#fff,stroke:#fff
    style id13 fill:#fff,stroke:#fff
```

::::

:::

# Suppression dans un arbre AVL 2.0

::: columns

:::: column

## Argl! 50 est déséquilibré!

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((50))-->id1((20));
    id0-->id2((100));
    id1-->id3((10));
    id1-->id4((40));
    id2-->id7((80))
    id2-->id8((200))
    id7-->id9((70))
    id7-->id10((90))
    id9-->id11((60))
    id9-->id12((  ))
    id8-->id13((  ))
    id8-->id14((300))
    style id12 fill:#fff,stroke:#fff
    style id13 fill:#fff,stroke:#fff
```

::::

:::: column

. . .

## Algorithme par problème: rotation DG autour de 50

```{.mermaid format=pdf width=400 loc=figs/}
graph TD;
    id0((80))-->id1((50));
    id0-->id2((100));
    id1-->id3((20));
    id1-->id4((70));
    id3-->id5((10));
    id3-->id6((40));
    id4-->id9((60))
    id4-->id10((  ))
    id2-->id7((90))
    id2-->id8((200))
    id8-->id13((  ))
    id8-->id14((300))
    style id10 fill:#fff,stroke:#fff
    style id13 fill:#fff,stroke:#fff
```

::::

:::

# Résumé de la suppression

1. On supprime comme pour un arbre binaire de recherche.
2. Si un nœud est déséquilibré, on le rééquilibre.
    * Cette opération peut déséquilibrer un autre nœud.
3. On continue à rééquilibrer tant qu'il y a des nœuds à équilibrer.
