diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..677fe33738df9566bdecddb9785d71753266bdcd --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Remerciements et contributions + +Merci aux contributeurs suivants pour leurs efforts (dans un ordre aléatoire): + +* P. Kunzli +* A. Boyer +* G. Legouic +* P. Albuquerque +* O. Malaspinas +* A. Escribano + diff --git a/slides/cours_15.md b/slides/cours_15.md index 4b1d29228ea3a4bee26480e9e7e1ab8eff1cab4f..09a8ed06a9c28de6eb60a4ad216f6dbdbddf54a6 100644 --- a/slides/cours_15.md +++ b/slides/cours_15.md @@ -707,7 +707,7 @@ void pretty_print(tree_t tree, int n) { printf(" "); } printf("%d\n", tree->info); - pretty_print(tree->left); + pretty_print(tree->left, n+1); } } ``` diff --git a/slides/cours_17.md b/slides/cours_17.md index 08564a1651cea79e581232c86890fec5076ede32..014b123603906078459f4cccf1270f923e0656be 100644 --- a/slides/cours_17.md +++ b/slides/cours_17.md @@ -320,6 +320,8 @@ R # Arbres AVL +\footnotesize + * Quand est-ce qu'on équilibre un arbre? . . . @@ -638,7 +640,7 @@ graph TD; ## Cas 2a -* `v1`, `v2`, `u`, `w` même hauteur. +* `h(v1)=h(v2), h(u)=h(w)`. * déséquilibre en `C` après insertion dans `v2`  @@ -653,7 +655,7 @@ graph TD; . . . -* ramène `u`, `v1`, `v2`, `w` à la même hauteur. +* 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`) diff --git a/slides/cours_18.md b/slides/cours_18.md new file mode 100644 index 0000000000000000000000000000000000000000..42a938892fdde21bcb25939c260ea8557b9b3c58 --- /dev/null +++ b/slides/cours_18.md @@ -0,0 +1,934 @@ +--- +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? + +```{.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` + + + +:::: + +:::: column + +## Cas 1a + +* Comment rééquilibrer? + +. . . + +* ramène `u`, `v` `w` à la même hauteur. +* `v` à droite de `A` (gauche de `B`) + + + +:::: + +::: + +# Les cas de déséquilibre + + +::: columns + +:::: column + +## Cas 1b (symétrique 1a) + + + +:::: + +:::: column + +## Cas 1b (symétrique 1a) + +* Comment rééquilibrer? + +. . . + + + +:::: + +::: + +# 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` + + + +:::: + +:::: 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`) + + + +:::: + +::: + + +# Les cas de déséquilibre + + +::: columns + +:::: column + +## Cas 2b (symétrique 2a) + + + +:::: + +:::: column + +## Cas 2b (symétrique 2a) + +* Comment rééquilibrer? + +. . . + + + +:::: + +::: + +# 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é +``` + +{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 + + + +# La rotation + +## La rotation gauche (5min, matrix) + + + +. . . + +\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 (5min)? + +. . . + +```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) + + + +# 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’equilibre. +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 pour déséquilibrer un autre nœud. +3. On continue à rééquilibrer tant qu'il y a des nœuds à équilibrer. diff --git a/slides/figs/double_rotation_gauche_droite.png b/slides/figs/double_rotation_gauche_droite.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e8cc8a1321c354d2adecb57a4e34bc5b98e5d2 Binary files /dev/null and b/slides/figs/double_rotation_gauche_droite.png differ diff --git a/slides/figs/facteur_equilibre.png b/slides/figs/facteur_equilibre.png new file mode 100644 index 0000000000000000000000000000000000000000..df60e129ff990ed2ae13647d5e1ca56ae739a9ef Binary files /dev/null and b/slides/figs/facteur_equilibre.png differ diff --git a/slides/figs/rotation_gauche_droite.png b/slides/figs/rotation_gauche_droite.png new file mode 100644 index 0000000000000000000000000000000000000000..28f7476188fc858ecd5fc37b32b933b2956f9d27 Binary files /dev/null and b/slides/figs/rotation_gauche_droite.png differ