diff --git a/slides/.gitignore b/slides/.gitignore index 2000f8a63a7707b72e472719255b506fcc21b692..311559fd6103ddbf587e46500afc3d3a06bb04d6 100644 --- a/slides/.gitignore +++ b/slides/.gitignore @@ -3,3 +3,4 @@ *.markdown *.html index.md +.puppeteer.json diff --git a/slides/.puppeteer.json b/slides/.puppeteer.json deleted file mode 100644 index 5de4752f0cc5ab97cd3b7391827c2ebe37a75ee8..0000000000000000000000000000000000000000 --- a/slides/.puppeteer.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "executablePath": "/usr/bin/chromium-browser", - "args": ["--no-sandbox"] -} diff --git a/slides/cours_16.md b/slides/cours_16.md index c6bb833b870f694611e9b9c7c8f2248470295dd6..f487d541ff9932de59ffcca25b8ac02e870ee152 100644 --- a/slides/cours_16.md +++ b/slides/cours_16.md @@ -278,6 +278,7 @@ arbre suppression(arbre, clé) arbre parent(arbre, sous_arbre) si est_non_vide(arbre) actuel = arbre + parent = actuel clé = clé(sous_arbre) faire si (clé != clé(actuel)) @@ -319,15 +320,17 @@ arbre suppression(arbre, clé) # Le pseudo-code de la suppression +\footnotesize + ## Pour au moins deux enfants (ensemble) ``` arbre suppression(arbre, clé) sous_arbre = position(arbre, clé) # on revérifie pas que c'est bien la clé si est_non_vide(gauche(sous_arbre)) et est_non_vide(droite(sous_arbre)) - max_gauche = position(sous_arbre, clé) + max_gauche = position(gauche(sous_arbre), clé) échange(clé(max_gauche), clé(sous_arbre)) - suppression(sous_arbre, clé) # + suppression(gauche(sous_arbre), clé) ``` # Exercices (poster sur matrix) @@ -1196,112 +1199,3 @@ graph TD; * Postez le résultat sur matrix. -# L'algorithme du tri par tas (1/4) - -## Deux étapes - -1. Entassement (tamisage): transformer l'arbre en tas. -2. Échanger la racine avec le dernier élément et entasser la racine. - -## Pseudo-code d'entassement de l'arbre (5 min, matrix) - -. . . - -``` -tri_par_tas(tab) - entassement(tab) - échanger(tab[0], tab[size(tab)-1]) - pour i = size(tab)-1 à 2 - promotion(tab, i) - échanger(tab[0], tab[i-1]) -entassement(tab) - pour i = size(tab) / 2 - 1 jusqu'à 0 - promotion(tab, i) -promotion(tab, i) - ind_max = ind_max(tab, i, gauche(i), droite(i)) - si i != ind_max - échanger(tab[i], tab[ind_max]) - promotion(tab, ind_max) -``` - -# L'algorithme du tri par tas (2/4) - -* Fonctions utilitaires - -``` -int ind_max(tab, i, g, d) - ind_max = i - si tab[ind_max] < tab[l] - ind_max = l - si tab[ind_mx] < tab[r] - ind_max = r - retourne ind_max -int gauche(i) - retourne 2 * i + 1 -int droite(i) - retourne 2 * i + 2 -``` - - -# L'algorithme du tri par tas (3/4) - -\footnote size - -## Implémenter en C l'algorithme du tri par tas (matrix, 20min) - -. . . - -```C -void heapsort(int size, int tab[size]) { - heapify(size, tab); - swap(tab, tab + size - 1); - for (int s = size - 1; s > 1; s--) { - sift_up(s, tab, 0); - swap(tab, tab + s - 1); - } -} -void heapify(int size, int tab[size]) { - for (int i = size / 2 - 1; i >= 0; i--) { - sift_up(size, tab, i); - } -} -void sift_up(int size, int tab[size], int i) { - int ind_max = ind_max3(size, tab, i, left(i), right(i)); - if (i != ind_max) { - swap(tab + i, tab + ind_max); - sift_up(size, tab, ind_max); - } -} -``` - -# L'algorithme du tri par tas (3/4) - -\footnotesize - -## Fonctions utilitaires - -. . . - -```C -int ind_max3(int size, int tab[size], int i, int l, int r) { - int ind_max = i; - if (l < size && tab[ind_max] < tab[l]) { - ind_max = l; - } - if (r < size && tab[ind_max] < tab[r]) { - ind_max = r; - } - return ind_max; -} -void swap(int *a, int *b) { - int tmp = *a; - *a = *b; - *b = tmp; -} -int left(int i) { - return 2 * i + 1; -} -int right(int i) { - return 2 * i + 2; -} -``` diff --git a/slides/cours_17.md b/slides/cours_17.md new file mode 100644 index 0000000000000000000000000000000000000000..e41523f00020741c847c4c1a4257db2f2fc531c1 --- /dev/null +++ b/slides/cours_17.md @@ -0,0 +1,1129 @@ +--- +title: "Tri par tas et arbres AVL" +date: "2022-03-09" +patat: + eval: + tai: + command: fish + fragment: false + replace: true + ccc: + command: fish + fragment: false + replace: true + images: + backend: auto +--- + +# Questions sur les notions du dernier cours + +* Comment représenter un tableau sous forme d'arbre binaire? + +. . . + +* Qu'est-ce qu'un tas? + +# Exemple de tri par tas (1/N) + +``` + | 1 | 16 | 5 | 12 | 4 | 2 | 8 | 10 | 6 | 7 | +``` + +::: columns + +:::: column + +* Quel est l'arbre que cela représente? + +. . . + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((16)); + id0-->id2((5)); + id1-->id3((12)); + id1-->id4((4)); + id2-->id5((2)); + id2-->id6((8)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((7)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Transformer l'arbre en tas. + +* On commence à l'indice $N/2 = 5$: `4`. +* `7 > 4` (enfant `>` parent). +* intervertir `4` et `7`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((16)); + id0-->id2((5)); + id1-->id3((12)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((8)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +::: + +. . . + +``` + * * + | 1 | 16 | 5 | 12 | 7 | 2 | 8 | 10 | 6 | 4 | +``` + +# Exemple de tri par tas (2/N) + +``` + | 1 | 16 | 5 | 12 | 7 | 2 | 8 | 10 | 6 | 4 | +``` + +::: columns + +:::: column + +**But:** Transformer l'arbre en tas. + +* On continue à l'indice $N/2-1 = 4$: `12`. +* Déjà un tas, rien à faire. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((16)); + id0-->id2((5)); + id1-->id3((12)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((8)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Transformer l'arbre en tas. + +* On continue à l'indice $N/2-2 = 3$: `5`. +* `5 < 8`, échanger `8` et `5` (aka `max(2, 5, 8)`) + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((16)); + id0-->id2((8)); + id1-->id3((12)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +::: + +. . . + +``` + | 1 | 16 | 8 | 12 | 7 | 2 | 5 | 10 | 6 | 4 | +``` + +# Exemple de tri par tas (3/N) + +``` + | 1 | 16 | 5 | 12 | 7 | 2 | 8 | 10 | 6 | 4 | +``` + +::: columns + +:::: column + +**But:** Transformer l'arbre en tas. + +* Indice $N/2-1 = 4$: `12`. +* Déjà un tas, rien à faire. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((16)); + id0-->id2((5)); + id1-->id3((12)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((8)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Transformer l'arbre en tas. + +* Indice $N/2-2 = 3$: `5`. +* `5 < 8`, `5 <=> max(2, 5, 8)` + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((16)); + id0-->id2((8)); + id1-->id3((12)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +::: + +``` + * * + | 1 | 16 | 8 | 12 | 7 | 2 | 5 | 10 | 6 | 4 | +``` + +# Exemple de tri par tas (4/N) + +``` + | 1 | 16 | 8 | 12 | 7 | 2 | 5 | 10 | 6 | 4 | +``` + +::: columns + +:::: column + +**But:** Transformer l'arbre en tas. + +* Indice $N/2-3 = 1$: `16`. +* Déjà un tas, rien à faire. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((16)); + id0-->id2((8)); + id1-->id3((12)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Transformer l'arbre en tas. + +* Indice $N/2-4 = 1$: `1`. +* `1 < 16 && 1 < 8`, `1 <=> max(1, 16, 8)` + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((16))-->id1((1)); + id0-->id2((8)); + id1-->id3((12)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +::: + +``` + * * + | 16 | 1 | 8 | 12 | 7 | 2 | 5 | 10 | 6 | 4 | +``` + + +# Exemple de tri par tas (5/N) + +``` + | 16 | 1 | 8 | 12 | 7 | 2 | 5 | 10 | 6 | 4 | +``` + +::: columns + +:::: column + +**But:** Transformer l'arbre en tas. + +* Recommencer avec `1`. +* `1 <=> max(1, 12, 7)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((16))-->id1((12)); + id0-->id2((8)); + id1-->id3((1)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((10)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Transformer l'arbre en tas. + +* Recommencer avec `1`. +* `1 <=> max(1, 10, 6)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((16))-->id1((12)); + id0-->id2((8)); + id1-->id3((10)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((1)); + id3-->id8((6)); + id4-->id9((4)); + id4-->id10(( )); + style id10 fill:#fff,stroke:#fff +``` + +:::: + +::: + +``` + * * * + | 16 | 12 | 8 | 10 | 7 | 2 | 5 | 1 | 6 | 4 | +``` + +* L'arbre est un tas. + +# Exemple de tri par tas (6/N) + +``` + | 16 | 12 | 8 | 10 | 7 | 2 | 5 | 1 | 6 | 4 | +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `16` (`max` de l'arbre) avec `4`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((4))-->id1((12)); + id0-->id2((8)); + id1-->id3((10)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((1)); + id3-->id8((6)); +``` + +:::: + +:::: column + +**But:** Trier les tas. + +* `4 <=> max(4, 12, 8)`. +* `4 <=> max(4, 10, 7)`. +* `4 <=> max(4, 1, 6)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((12))-->id1((10)); + id0-->id2((8)); + id1-->id3((6)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((1)); + id3-->id8((4)); +``` + +:::: + +::: + +``` + | 12 | 10 | 8 | 6 | 7 | 2 | 5 | 1 | 4 || 16 +``` + + +# Exemple de tri par tas (7/N) + +``` + | 12 | 10 | 8 | 6 | 7 | 2 | 5 | 1 | 4 || 16 +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `12` (`max` de l'arbre) avec `4`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((4))-->id1((10)); + id0-->id2((8)); + id1-->id3((6)); + id1-->id4((7)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((1)); + id3-->id8(( )); + style id8 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Trier les tas. + +* `4 <=> max(4, 10, 8)`. +* `4 <=> max(4, 6, 7)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((10))-->id1((7)); + id0-->id2((8)); + id1-->id3((6)); + id1-->id4((4)); + id2-->id5((2)); + id2-->id6((5)); + id3-->id7((1)); + id3-->id8(( )); + style id8 fill:#fff,stroke:#fff +``` + +:::: + +::: + +``` + | 10 | 7 | 8 | 6 | 4 | 2 | 5 | 1 || 12 | 16 +``` + +# Exemple de tri par tas (8/N) + +``` + | 10 | 7 | 8 | 6 | 4 | 2 | 5 | 1 || 12 | 16 +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `10` (`max` de l'arbre) avec `1`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((7)); + id0-->id2((8)); + id1-->id3((6)); + id1-->id4((4)); + id2-->id5((2)); + id2-->id6((5)); +``` + +:::: + +:::: column + +**But:** Trier les tas. + +* `1 <=> max(1, 7, 8)`. +* `5 <=> max(1, 2, 5)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((8))-->id1((7)); + id0-->id2((5)); + id1-->id3((6)); + id1-->id4((4)); + id2-->id5((2)); + id2-->id6((1)); +``` + +:::: + +::: + +``` + | 8 | 7 | 5 | 6 | 4 | 2 | 1 || 10 | 12 | 16 +``` + +# Exemple de tri par tas (9/N) + +``` + | 8 | 7 | 5 | 6 | 4 | 2 | 1 || 10 | 12 | 16 +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `8` (`max` de l'arbre) avec `1`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((7)); + id0-->id2((5)); + id1-->id3((6)); + id1-->id4((4)); + id2-->id5((2)); + id2-->id6(( )); + style id6 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Trier les tas. + +* `1 <=> max(1, 7, 5)`. +* `1 <=> max(1, 6, 4)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((7))-->id1((6)); + id0-->id2((5)); + id1-->id3((1)); + id1-->id4((4)); + id2-->id5((2)); + id2-->id6(( )); + style id6 fill:#fff,stroke:#fff +``` + +:::: + +::: + +``` + | 7 | 6 | 5 | 1 | 4 | 2 || 8 | 10 | 12 | 16 +``` + +# Exemple de tri par tas (10/N) + +``` + | 7 | 6 | 5 | 1 | 4 | 2 || 8 | 10 | 12 | 16 +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `7` (`max` de l'arbre) avec `2`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((2))-->id1((6)); + id0-->id2((5)); + id1-->id3((1)); + id1-->id4((4)); +``` + +:::: + +:::: column + +**But:** Trier les tas. + +* `2 <=> max(2, 6, 5)`. +* `2 <=> max(2, 1, 4)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((6))-->id1((4)); + id0-->id2((5)); + id1-->id3((1)); + id1-->id4((2)); +``` + +:::: + +::: + +``` + | 6 | 4 | 5 | 1 | 2 || 8 | 10 | 12 | 16 +``` + +# Exemple de tri par tas (11/N) + +``` + | 6 | 4 | 5 | 1 | 2 || 8 | 10 | 12 | 16 +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `6` (`max` de l'arbre) avec `2`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((2))-->id1((4)); + id0-->id2((5)); + id1-->id3((1)); + id1-->id4(( )); + style id4 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Trier les tas. + +* `2 <=> max(2, 4, 5)`. +* `2 <=> max(2, 1, 4)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((5))-->id1((4)); + id0-->id2((2)); + id1-->id3((1)); + id1-->id4(( )); + style id4 fill:#fff,stroke:#fff +``` + +:::: + +::: + +``` + | 5 | 4 | 2 | 1 || 6 | 8 | 10 | 12 | 16 +``` + +# Exemple de tri par tas (12/N) + +``` + | 5 | 4 | 2 | 1 || 6 | 8 | 10 | 12 | 16 +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `5` (`max` de l'arbre) avec `1`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((1))-->id1((4)); + id0-->id2((2)); +``` + +:::: + +:::: column + +**But:** Trier les tas. + +* `1 <=> max(1, 4, 2)`. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((4))-->id1((1)); + id0-->id2((2)); +``` + +:::: + +::: + +``` + | 4 | 1 | 2 || 5 | 6 | 8 | 10 | 12 | 16 +``` + +# Exemple de tri par tas (13/N) + +``` + | 4 | 1 | 2 || 5 | 6 | 8 | 10 | 12 | 16 +``` + +::: columns + +:::: column + +**But:** Trier les tas. + +* Échanger la racine, `4` (`max` de l'arbre) avec `2`. +* Traiter la racine. + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((2))-->id1((1)); + id0-->id2(( )); + style id2 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +**But:** Trier les tas. Plus rien à trier + +* On fait les 2 dernières étapes en vitesse. +* Échange `2` avec `1`. +* Il reste que `1`. GGWP! + + +:::: + +::: + +``` + | 1 | 2 | 4 | 5 | 6 | 8 | 10 | 12 | 16 +``` + +# Exercice (10min) + +* Trier par tas le tableau + +``` + | 1 | 2 | 4 | 5 | 6 | 8 | 10 | 12 | 16 +``` + +* Mettez autant de détails que possible. +* Que constatez-vous? +* Postez le résultat sur matrix. + + +# L'algorithme du tri par tas (1/4) + +\footnotesize + +## Deux étapes + +1. Entassement (tamisage): transformer l'arbre en tas. +2. Échanger la racine avec le dernier élément et entasser la racine. + +## Pseudo-code d'entassement de l'arbre (5 min, matrix) + +. . . + +``` +tri_par_tas(tab) + entassement(tab) + échanger(tab[0], tab[size(tab)-1]) + pour i = size(tab)-1 à 2 + promotion(tab, 0) + échanger(tab[0], tab[i-1]) +entassement(tab) + pour i = size(tab) / 2 - 1 jusqu'à 0 + promotion(tab, i) +promotion(tab, i) + ind_max = ind_max(tab, i, gauche(i), droite(i)) + si i != ind_max + échanger(tab[i], tab[ind_max]) + promotion(tab, ind_max) +``` + +# L'algorithme du tri par tas (2/4) + +* Fonctions utilitaires + +``` +int ind_max(tab, i, g, d) + ind_max = i + si tab[ind_max] < tab[l] + ind_max = l + si tab[ind_mx] < tab[r] + ind_max = r + retourne ind_max +int gauche(i) + retourne 2 * i + 1 +int droite(i) + retourne 2 * i + 2 +``` + + +# L'algorithme du tri par tas (3/4) + +\footnotesize + +## Implémenter en C l'algorithme du tri par tas (matrix, 20min) + +. . . + +```C +void heapsort(int size, int tab[size]) { + heapify(size, tab); + swap(tab, tab + size - 1); + for (int s = size - 1; s > 1; s--) { + sift_up(s, tab, 0); + swap(tab, tab + s - 1); + } +} +void heapify(int size, int tab[size]) { + for (int i = size / 2 - 1; i >= 0; i--) { + sift_up(size, tab, i); + } +} +void sift_up(int size, int tab[size], int i) { + int ind_max = ind_max3(size, tab, i, left(i), right(i)); + if (i != ind_max) { + swap(tab + i, tab + ind_max); + sift_up(size, tab, ind_max); + } +} +``` + +# L'algorithme du tri par tas (4/4) + +\footnotesize + +## Fonctions utilitaires + +. . . + +```C +int ind_max3(int size, int tab[size], int i, int l, int r) { + int ind_max = i; + if (l < size && tab[ind_max] < tab[l]) { + ind_max = l; + } + if (r < size && tab[ind_max] < tab[r]) { + ind_max = r; + } + return ind_max; +} +void swap(int *a, int *b) { + int tmp = *a; + *a = *b; + *b = tmp; +} +int left(int i) { + return 2 * i + 1; +} +int right(int i) { + return 2 * i + 2; +} +``` + + +# Complexités + +::: columns + +:::: column + +## Complexité de la recherche + +1. En moyenne? +2. Dans le pire des cas? + +. . . + +1. $O(\log_2(N))$ +2. $O(N)$ + +:::: + +:::: column + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((10))-->id1((9)); + id0-->id8(( )); + id1-->id2((7)); + id1-->id9(( )); + id2-->id3((6)); + id2-->id10(( )); + id3-->id4((5)); + id3-->id11(( )); + style id8 fill:#fff,stroke:#fff + style id9 fill:#fff,stroke:#fff + style id10 fill:#fff,stroke:#fff + style id11 fill:#fff,stroke:#fff +``` + +:::: + +::: + +# Un meilleur arbre + +* Quelle propriété doit satisfaire un arbre pour être $O(\log_2(N))$? + +. . . + +* Si on a environ le même nombre de noeuds dans les sous-arbres. + +## Définition + +Un arbre binaire est parfaitement équilibré si, pour chaque +nœud, la différence entre les nombres de nœuds des sous- +arbres gauche et droit vaut au plus 1. + +* Si l'arbre est **parfaitement équilibré**, alors tout ira bien. +* Quelle est la hauteur (profondeur) d'un arbre parfaitement équilibré? + +. . . + +* $O(\log_2(N))$. + + +# Équilibre parfait ou pas? + +::: columns + +:::: column + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((W))-->id1((B)); + id0-->id8((Y)); + id1-->id2((A)); + id1-->id9(( )); + id8-->id10((X)); + id8-->id11(( )); + style id9 fill:#fff,stroke:#fff + style id11 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +. . . + +``` +É +Q +U +I +L +I +B +R +É +``` + +:::: + +::: + +# Équilibre parfait ou pas? + +::: columns + +:::: column + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((16))-->id1((10)); + id0-->id2((19)); + id1-->id3((8)); + id1-->id4((12)); + id4-->id5((11)); + id4-->id6(( )); + id2-->id7((17)); + id2-->id8(( )); + id7-->id9(( )); + id7-->id10((18)); + style id6 fill:#fff,stroke:#fff + style id8 fill:#fff,stroke:#fff + style id9 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +. . . + +``` +P +A +S + +É +Q +U +I +L +I +B +R +É +``` + +:::: + +::: + +# Arbres AVL + +* Quand est-ce qu'on équilibre un arbre? + +. . . + +* A l'insertion/suppression. +* Maintenir un arbre en état d'équilibre parfait: cher (insertion, suppression). +* On peut "relaxer" la condition d'équilibre: profondeur (hauteur) au lieu du + nombre de neouds: + * La hauteur $\sim\log_2(N)$. + +## Définition + +Un arbre AVL (Adelson-Velskii et Landis) est un arbre binaire de recherche dans +lequel, pour chaque nœud, la différence de hauteur entre le sous-arbre gauche et droit vaut au plus 1. + +* Relation entre noeuds et hauteur: +$$ +\log_2(1+N)\leq 1+H\leq 1.44\cdot\log_2(2+N),\quad N=10^5,\ 17\leq H \leq 25. +$$ +* Permet l'équilibrage en temps constant: insertion/suppression $O(\log_2(N))$. + +# Notation + +* `hg`: hauteur du sous-arbre gauche. +* `hd`: hauteur du sous-arbre droit. +* `facteur d'équilibre = fe = hd - hg` +* Que vaut `fe` si l'arbre est AVL? + +. . . + +* `fe = {-1, 0, 1}` + + +# AVL ou pas? + +::: columns + +:::: column + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((12))-->id1((10)); + id0-->id2((19)); + id2-->id3((17)); + id2-->id4((97)); +``` + +:::: + +:::: column + +. . . + +``` +A +V +L +``` + +:::: + +::: + +# AVL ou pas? + +::: columns + +:::: column + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((12))-->id1((1)); + id0-->id2((19)); + id2-->id3((17)); + id2-->id4((97)); + id4-->id5((37)); + id4-->id6(( )); + style id6 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +. . . + +``` +P +A +S + +A +V +L +``` + +:::: + +::: + diff --git a/slides/cours_18.md b/slides/cours_18.md new file mode 100644 index 0000000000000000000000000000000000000000..a2d1cd07aa272936a5808187eb0f80270bb869a9 --- /dev/null +++ b/slides/cours_18.md @@ -0,0 +1,1022 @@ +--- +title: "Tri par tas et arbres AVL" +date: "2022-03-16" +patat: + eval: + tai: + command: fish + fragment: false + replace: true + ccc: + command: fish + fragment: false + replace: true + images: + backend: auto +--- + +# 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}`. + +# 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 (1/N) + +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)); +``` + +:::: + +:::: column + +. . . + +* `hd = hg` + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((12))-->id1((1)); + id0-->id2((19)); + id1-->id4(( )); + id1-->id5((4)); + style id4 fill:#fff,stroke:#fff +``` + +* `fe = -1` + +:::: + +::: + +# Insertion dans un arbre AVL (2/N) + +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)); + id2-->id3((18)); + id2-->id4(( )); + style id4 fill:#fff,stroke:#fff +``` + +:::: + +:::: column + +. . . + +* `hd < hg` + +```{.mermaid format=pdf width=400 loc=figs/} +graph TD; + id0((12))-->id1((1)); + id0-->id2((19)); + id2-->id3((18)); + id2-->id4(( )); + id1-->id5(( )); + id1-->id6((4)); + style id4 fill:#fff,stroke:#fff + style id5 fill:#fff,stroke:#fff +``` + +* `fe = 0` + +:::: + +::: + +# Insertion dans un arbre AVL (3/N) + +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 + +* `v1`, `v2`, `u`, `w` même hauteur. +* déséquilibre en `C` après insertion dans `v2` + + + +:::: + +:::: column + +## Cas 2a + +* Comment rééquilibrer? + +. . . + +* ramène `u`, `v1`, `v2`, `w` à la même hauteur. +* `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(gauche(P)) = -1 => cas 1b +fe(P) = +2 && fe(gauche(P)) = +1 => cas 2b +``` + +## Dessiner les différents cas, sur le dessin ci-dessous + + + +# La rotation + +## La rotation gauche (5min, matrix) + + + +. . . + +``` +arbre rotation_gauche(arbre P) + si est_non_vide(P) + Q = droite(P) + droite(P) = gauche(Q) + gauche(Q) = droite(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) = droite(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)` + +. . . + +```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->lefe; + } + 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é 15min) + +. . . + +::: 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 noeuds 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 à 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 noeud est déséquilibré, on le rééquilibre. + * Cette opération pour déséquilibrer un autre noeud. +3. On continue à rééquilibrer tant qu'il y a des noeuds à équilibrer. diff --git a/slides/figs/cas1a_droite.png b/slides/figs/cas1a_droite.png new file mode 100644 index 0000000000000000000000000000000000000000..9b7b92157e5fe1fa53b7f0e20ecc87f97571caff Binary files /dev/null and b/slides/figs/cas1a_droite.png differ diff --git a/slides/figs/cas1a_gauche.png b/slides/figs/cas1a_gauche.png new file mode 100644 index 0000000000000000000000000000000000000000..c325d8b25cb13e568f24213131d8d77511a9e1ab Binary files /dev/null and b/slides/figs/cas1a_gauche.png differ diff --git a/slides/figs/cas1b_droite.png b/slides/figs/cas1b_droite.png new file mode 100644 index 0000000000000000000000000000000000000000..34344efd9b740261e00c43b30a4c6f9890b74e7b Binary files /dev/null and b/slides/figs/cas1b_droite.png differ diff --git a/slides/figs/cas1b_gauche.png b/slides/figs/cas1b_gauche.png new file mode 100644 index 0000000000000000000000000000000000000000..050eceea5d8a28b24d7c2684ccb4f0f5a0b10cd8 Binary files /dev/null and b/slides/figs/cas1b_gauche.png differ diff --git a/slides/figs/cas2a_droite.png b/slides/figs/cas2a_droite.png new file mode 100644 index 0000000000000000000000000000000000000000..f04fb57308b3aecca93f553005a0b611a158ebca Binary files /dev/null and b/slides/figs/cas2a_droite.png differ diff --git a/slides/figs/cas2a_gauche.png b/slides/figs/cas2a_gauche.png new file mode 100644 index 0000000000000000000000000000000000000000..3ef07573f717b27cc49e97209bb34811c16a5319 Binary files /dev/null and b/slides/figs/cas2a_gauche.png differ diff --git a/slides/figs/cas2b_droite.png b/slides/figs/cas2b_droite.png new file mode 100644 index 0000000000000000000000000000000000000000..f61d56e332600f56aade1584dc579dd1708e1791 Binary files /dev/null and b/slides/figs/cas2b_droite.png differ diff --git a/slides/figs/cas2b_gauche.png b/slides/figs/cas2b_gauche.png new file mode 100644 index 0000000000000000000000000000000000000000..96474155d1814f0f945f1dfe19cf9bb6508ef148 Binary files /dev/null and b/slides/figs/cas2b_gauche.png differ 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 diff --git a/slides/gen_index.sh b/slides/gen_index.sh index 507d3f8f21405d2b295cacd80bd1170aeda8a0b9..5c72edf6c43ccbb286b6af2401b7c0e789f0a267 100755 --- a/slides/gen_index.sh +++ b/slides/gen_index.sh @@ -1,5 +1,26 @@ #!/bin/bash +set -e + +function get_info() { + local field=$(echo "$fullName" | sed "$2q;d" $1); + IFS=$3; + local field=($field); + if [ "${field}" != $5 ]; then + return 1 + fi + local field=${field[1]}; + IFS=$4; + local field=($field); + local field=${field[1]}; + echo "$field" +} + +function fail() { + printf '%s\n' "$1" >&2 ## Send message to stderr. + exit "${2-1}" ## Return a code specified by $2, or 1 by default. +} + OIFS=$IFS NUM_LINE=2 PREFIX="" @@ -8,36 +29,27 @@ PREFIX="" classes=() for i in *.md; do [ -f "$i" ] || break - comp=$(echo "$fullName" | sed "${NUM_LINE}q;d" $i) - date=$(echo "$fullName" | sed "3q;d" $i) - IFS=':' - comp=($comp); - comp=${comp[1]} - date=($date); - date=${date[1]} - # echo $comp - IFS='"' - comp=($comp) - comp=${comp[1]} - date=($date); - date=${date[1]} - # echo $comp | awk '{ print substr( $0, 1, length($0)-1 ) }' - # echo $comp - # date=sed "${NUM_LINE}q;d" $i + date="$(get_info $i 3 ":" '"' "date")" + if [ "$date" == 1 ]; then + fail "Error date field not found" + fi + comp="$(get_info $i 2 ":" '"' "title")" + if [ "$comp" == 1 ]; then + fail "Error title field not found" + fi i="${i%.*}" class="[${date} ${comp}](${PREFIX}${i}.pdf)" - classes+=($class) - # echo "[${date} ${comp}](${PREFIX}${i}.pdf)" >> index.md + classes+=("$class") done IFS=$'\n' classes=($(sort <<<"${classes[*]}")) date=$(date '+%Y-%m-%d') echo "---" >> index.md -echo "title: Slides du cours d'Algorithmique" >> index.md -echo "date: ${date}" >> index.md +echo "title: \"Slides du cours d'algorithmique\"" >> index.md +echo "date: \"${date}\"" >> index.md echo "---" >> index.md echo "" >> index.md -echo "# Tous les slides du cours d'Algorithmique" >> index.md +echo "# Tous les slides du cours d'algorithmique" >> index.md echo "" >> index.md for i in ${classes[*]}; do echo "* $i" >> index.md diff --git a/source_codes/arbres_AVL/.gitignore b/source_codes/arbres_AVL/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f8a1ca8adedba78aa24db2659b28c80e68e737f0 --- /dev/null +++ b/source_codes/arbres_AVL/.gitignore @@ -0,0 +1,4 @@ +bin_tree.o +avl.o +main +main.o diff --git a/source_codes/arbres_AVL/Makefile b/source_codes/arbres_AVL/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..88318d040b26be3d320f34562fdb9066f4b418ea --- /dev/null +++ b/source_codes/arbres_AVL/Makefile @@ -0,0 +1,25 @@ +CC:=gcc +# SAN:=-fsanitize=address +CFLAGS:=-Wall -Wextra -pedantic -g $(SAN) +LDFLAGS:=-lm $(SAN) +SOURCES := $(wildcard *.c) +OBJECTS := $(patsubst %.c, %.o, $(SOURCES)) + +all: main $(OBJECTS) + +main: main.c bin_tree.o avl.o + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + @echo $@ >> .gitignore + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + @echo $@ >> .gitignore + +bin_tree.o: bin_tree.h +avl.o: avl.h + +.PHONY: clean all + +clean: + rm -f *.o main .gitignore + diff --git a/source_codes/arbres_AVL/avl.c b/source_codes/arbres_AVL/avl.c new file mode 100644 index 0000000000000000000000000000000000000000..4c5cbce1aa7d1ffab08e85141f009e98f29a72bd --- /dev/null +++ b/source_codes/arbres_AVL/avl.c @@ -0,0 +1,174 @@ +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <assert.h> +#include <stdbool.h> +#include "avl.h" + +void avl_print(arbre tree,int N) { + if (N <= 0) { + N = 1; + } + if (NULL != tree) { + avl_print(tree->child[1],N+2); + for (int i=0;i<N;i++) { + printf(" "); + } + printf("%d\n",tree->key); + avl_print(tree->child[0],N+2); + } +} + +node* avl_desequilibre(arbre tree,clef key) { + node* crt = tree; + node* parent = NULL; + int h_prec[2] = {0,0}; + + while (NULL != crt && crt->key != key) { + if (abs(crt->h[1]-crt->h[0]) == 2) { + parent = crt; + h_prec[0] = parent->h[0]; + h_prec[1] = parent->h[1]; + parent->h[key > parent->key] -= 1; + } + crt = crt->child[key > crt->key]; + } + if (NULL != parent) { + parent->h[0] = h_prec[0]; + parent->h[1] = h_prec[1]; + } + return parent; +} + +int avl_height(arbre tree) { + if (NULL == tree) { + return 0; + } else { + return 1+fmax(avl_height(tree->child[0]),avl_height(tree->child[1]))+0.01; + } +} + +void avl_heights(arbre tree) { + for (int i=0;i<2;i++) { + if (NULL != tree->child[i]) { + avl_heights(tree->child[i]); + tree->h[i] = 1+fmax(tree->child[i]->h[0],tree->child[i]->h[1])+0.01; + } else { + tree->h[i] = 0; + } + } +} + +void avl_height_node(node* nd) { + for (int i=0;i<2;i++) { + if (NULL != nd->child[i]) { + nd->h[i] = 1+fmax(nd->child[i]->h[0],nd->child[i]->h[1])+0.01; + } else { + nd->h[i] = 0; + } + } +} + +static node* avl_rot(node* P,bool right) { + node* Q = NULL; + if (NULL != P) { + Q = P->child[right]; + P->child[right] = Q->child[!right]; + Q->child[!right] = P; + avl_height_node(P); + avl_height_node(Q); + } + return Q; +} + +node* avl_rot_g(node* nd) { + return avl_rot(nd,false); +} + +node* avl_rot_d(node* nd) { + return avl_rot(nd,true); +} + +static node* avl_rot2(node* nd,bool dg) { + nd->child[dg] = avl_rot(nd->child[dg],dg); + return avl_rot(nd,!dg); +} + +node* avl_rot_gd(node* nd) { + return avl_rot2(nd,false); +} + +node* avl_rot_dg(node* nd) { + return avl_rot2(nd,true); +} + +static void avl_rotation(node* nd,bool right) { + node* new_nd = calloc(1,sizeof(node)); + new_nd->key = nd->key; + new_nd->child[right] = nd->child[right]; + new_nd->child[!right] = nd->child[!right]->child[right]; + node* tmp = nd->child[!right]; + + nd->key = nd->child[!right]->key; + nd->child[right] = new_nd; + nd->child[!right] = nd->child[!right]->child[!right]; + avl_height_node(new_nd); + avl_height_node(nd); + free(tmp); +} + +void avl_rotation_g(node* nd) { + avl_rotation(nd,false); +} + +void avl_rotation_d(node* nd) { + avl_rotation(nd,true); +} + +static void avl_rotation2(node* nd,bool dg) { + avl_rotation(nd->child[dg],dg); + avl_rotation(nd,!dg); +} + +void avl_rotation_gd(node* nd) { + avl_rotation2(nd,false); +} + +void avl_rotation_dg(node* nd) { + avl_rotation2(nd,true); +} + +void avl_reequilibre(node* nd) { + switch(nd->h[1]-nd->h[0]) { + case +2: + switch(nd->child[1]->h[1] - nd->child[1]->h[0]) { + case +1: avl_rotation_g(nd); break; + case -1: avl_rotation_dg(nd); + } + break; + case -2: + switch(nd->child[0]->h[1] - nd->child[0]->h[0]) { + case -1: avl_rotation_d(nd); break; + case +1: avl_rotation_gd(nd); + } + } +} + +void avl_insert(clef key,arbre* tree,arbre* deseq) { + if (NULL == *tree) { + *tree = calloc(1,sizeof(node)); + (*tree)->key = key; + *deseq = NULL; + } else { + avl_insert(key,&((*tree)->child[key > (*tree)->key]),deseq); + if (NULL == *deseq) { + (*tree)->h[key > (*tree)->key] + = 1+fmax((*tree)->child[key > (*tree)->key]->h[0], + (*tree)->child[key > (*tree)->key]->h[1]); + } + if (abs((*tree)->h[1]-(*tree)->h[0]) == 2 && NULL == *deseq) { + *deseq = *tree; + } + } +} + diff --git a/source_codes/arbres_AVL/avl.h b/source_codes/arbres_AVL/avl.h new file mode 100644 index 0000000000000000000000000000000000000000..9f31a45de877550098b9ace6e2447bcb0e08a21b --- /dev/null +++ b/source_codes/arbres_AVL/avl.h @@ -0,0 +1,87 @@ +#ifndef AVL_H +#define AVL_H + +typedef int clef; + +typedef struct _node { + clef key; + struct _node* child[2]; + int h[2]; +} node; + +typedef node* arbre; + +//---------------------------------------------------------- +// fonction qui imprime un arbre -- +//---------------------------------------------------------- +void avl_print(arbre tree,int N); +//---------------------------------------------------------- +// fonction qui retourne le premier noeud d�s�quilibr� et -- +// met � jour les hauteurs sur le chemin d'insertion -- +//---------------------------------------------------------- +node* avl_desequilibre(arbre tree,clef key); +//---------------------------------------------------------- +// fonction qui calcule la hauteur d'un arbre -- +//---------------------------------------------------------- +int avl_height(arbre tree); +//---------------------------------------------------------- +// fonction qui remet � jour les hauteurs des noeuds -- +// apr�s le r��quilibrage -- +//---------------------------------------------------------- +void avl_heights(arbre tree); +//---------------------------------------------------------- +// fonction qui remet � jour les hauteurs des noeuds -- +// apr�s le r��quilibrage -- +//---------------------------------------------------------- +void avl_height_node(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une rotation gauche sur le -- +// noeud d�s�quilibr� -- +//---------------------------------------------------------- +node* avl_rot_g(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une rotation droite sur le -- +// noeud d�s�quilibr� -- +//---------------------------------------------------------- +node* avl_rot_d(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une double rotation gauche -- +// droite sur le noeud d�s�quilibr� -- +//---------------------------------------------------------- +node* avl_rot_gd(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une double rotation droite -- +// gauche sur le noeud d�s�quilibr� -- +//---------------------------------------------------------- +node* avl_rot_dg(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une rotation gauche sur le -- +// noeud d�s�quilibr� -- +//---------------------------------------------------------- +void avl_rotation_g(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une rotation droite sur le -- +// noeud d�s�quilibr� -- +//---------------------------------------------------------- +void avl_rotation_d(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une double rotation gauche -- +// droite sur le noeud d�s�quilibr� -- +//---------------------------------------------------------- +void avl_rotation_gd(node* nd); +//---------------------------------------------------------- +// fonction qui effectue une double rotation droite -- +// gauche sur le noeud d�s�quilibr� -- +//---------------------------------------------------------- + void avl_rotation_dg(node* nd); +//---------------------------------------------------------- +// fonction qui r��quilibre l'arbre -- +//---------------------------------------------------------- +void avl_reequilibre(node* nd); +//---------------------------------------------------------- +// fonction qui ins�re une valeur dans l'arbre -- +//---------------------------------------------------------- +void avl_insert(clef key,arbre* tree, arbre* deseq); + +#endif + diff --git a/source_codes/arbres_AVL/bin_tree.c b/source_codes/arbres_AVL/bin_tree.c new file mode 100644 index 0000000000000000000000000000000000000000..5a38e140a09d76ed2fb3c03acdd4419cde92b784 --- /dev/null +++ b/source_codes/arbres_AVL/bin_tree.c @@ -0,0 +1,127 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <stdbool.h> +#include <math.h> +#include "bin_tree.h" + +static node* position(arbre tree,int cle) { + node* crt = tree; + if (NULL != crt) { + while (cle != crt->key + && NULL != crt->child[(cle > crt->key)]) { + crt = crt->child[(cle > crt->key)]; + } + } + return crt; +} + +int arbre_depth(arbre tree) { + if (NULL == tree) { + return 0; + } else { + return 1+fmax(arbre_depth(tree->child[0]),arbre_depth(tree->child[1])); + } +} + +int arbre_size(arbre tree) { + if (NULL == tree) { + return 0; + } else { + return 1+arbre_size(tree->child[0])+arbre_size(tree->child[1]); + } +} + +bool arbre_insert(arbre* tree,int cle) { + if (NULL == *tree) { + *tree = calloc(1,sizeof(node)); + (*tree)->key = cle; + } else { + node* nd = position(*tree,cle); + if (cle != nd->key) { + nd->child[(cle > nd->key)] = calloc(1,sizeof(node)); + nd->child[(cle > nd->key)]->key = cle; + } else { + return false; + } + } + return true; +} + +static node* parent(arbre tree,node* nd) { + assert(NULL != tree && NULL != nd); + node* parent = NULL; + if (nd != tree) { + node* crt = tree; + int cle = nd->key; + do { + parent = crt; + if (cle != crt->key) { + crt = crt->child[(cle > crt->key)]; + } + } while (crt != nd); + } + return parent; +} + + + + + + + +bool arbre_delete(arbre* tree,int cle) { + node* nd = position(*tree,cle); + + if (NULL == nd || cle != nd->key) { + return false; + } + + // terminal node + if (NULL == nd->child[0] && NULL == nd->child[1]) { + node* nd_parent = parent(*tree,nd); + if (NULL == nd_parent) { // single node tree + *tree = NULL; + } else { + nd_parent->child[(nd == nd_parent->child[1])] = NULL; + } + free(nd); + return true; + } + + for (int ind=0;ind<2;ind++) { + if (NULL != nd->child[ind]) { + node* next = position(nd->child[ind],cle); + int val = next->key; + if (NULL == nd->child[ind]->child[ind^1]) { + nd->child[ind] = next->child[ind]; + free(next); + } else { + bool res = arbre_delete(tree,next->key); + } + nd->key = val; + return true; + } + } +} + +void arbre_print(arbre tree,int N) { + if (N <= 0) { + N = 1; + } + if (NULL != tree) { + arbre_print(tree->child[1],N+1); + for (int i=0;i<N;i++) { + printf(" "); + } + printf("%d\n",tree->key); + arbre_print(tree->child[0],N+1); + } +} + +bool arbre_search(arbre tree,int cle) { + node* nd = position(tree,cle); + return (NULL != nd && cle == nd->key); +} + + diff --git a/source_codes/arbres_AVL/bin_tree.h b/source_codes/arbres_AVL/bin_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..25843d5df1a9430ea0d58997f84289b166b5dcc8 --- /dev/null +++ b/source_codes/arbres_AVL/bin_tree.h @@ -0,0 +1,39 @@ +#ifndef BIN_TREE_H +#define BIN_TREE_H + +// Structure pour un arbre binaire +typedef int cle; +typedef struct _node { + cle key; + struct _node* child[2]; +} node; +typedef node* arbre; + +// Fonctionnalités pour un arbre binaire ordonné +bool arbre_search(arbre tree,int cle); +bool arbre_insert(arbre* tree,int cle); +bool arbre_delete(arbre* tree,int cle); +void arbre_print(arbre tree,int N); +int arbre_depth(arbre tree); +int arbre_size(arbre tree); +#endif + + + + + + + + + + + + + + + + + + + + diff --git a/source_codes/arbres_AVL/main.c b/source_codes/arbres_AVL/main.c new file mode 100644 index 0000000000000000000000000000000000000000..3454c3982330b2606b2b840f92f9b46a7bb396e4 --- /dev/null +++ b/source_codes/arbres_AVL/main.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <assert.h> +#include <stdbool.h> +#include "avl.h" + +void main() { + arbre mon_arbre = NULL, deseq = NULL; + char nbr[20]; + while (true) { + printf("Nombre: "); + scanf("%s",nbr); + if (strcmp(nbr,"quit") == 0) break; + avl_insert(atoi(nbr),&mon_arbre,&deseq); + if (NULL != deseq) { + printf("Desequilibre!"); + avl_reequilibre(deseq); + } + printf("\n\n"); + avl_print(mon_arbre,1); + printf("\n\n"); + } +} diff --git a/source_codes/arbres_binaires/.gitignore b/source_codes/arbres_binaires/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..87605a2522b98767e8215384d43a1d4012b565d8 --- /dev/null +++ b/source_codes/arbres_binaires/.gitignore @@ -0,0 +1,9 @@ +bin_tree.o +main +tree_search +bin_tree_main +arbre_binaire.o +bin_tree_main.o +bin_tree_part.o +main.o +tree_search.o diff --git a/source_codes/arbres_binaires/Makefile b/source_codes/arbres_binaires/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..28afaca45224d2847e47cd133713903d23187258 --- /dev/null +++ b/source_codes/arbres_binaires/Makefile @@ -0,0 +1,33 @@ +CC:=gcc +# SAN:=-fsanitize=address +CFLAGS:=-Wall -Wextra -pedantic -g $(SAN) +LDFLAGS:=-lm $(SAN) +SOURCES := $(wildcard *.c) +OBJECTS := $(patsubst %.c, %.o, $(SOURCES)) + +all: main tree_search bin_tree_main $(OBJECTS) + +tree_search: tree_search.c bin_tree.o + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + @echo $@ >> .gitignore + +bin_tree_main: bin_tree_main.c bin_tree.o + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + @echo $@ >> .gitignore + +main: main.c bin_tree.o + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) + @echo $@ >> .gitignore + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + @echo $@ >> .gitignore + +bin_tree.o: bin_tree.h +bin_tree_rec.o: bin_tree_rec.h + +.PHONY: clean all + +clean: + rm -f *.o main tree_search bin_tree_main .gitignore + diff --git a/source_codes/arbres_binaires/arbre_binaire.c b/source_codes/arbres_binaires/arbre_binaire.c new file mode 100644 index 0000000000000000000000000000000000000000..4a6a655d14b30ff00b0b96b2ba857c4df0086c0e --- /dev/null +++ b/source_codes/arbres_binaires/arbre_binaire.c @@ -0,0 +1,132 @@ +#include "arbre_binaire.h" +#include <assert.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +static node *position(arbre tree, int cle) { + node *crt = tree; + if (NULL != tree) { + do { + if (cle < crt->key) { + if (NULL == crt->gauche) { + break; + } + crt = crt->gauche; + } else if (cle > crt->key) { + if (NULL == crt->droite) { + break; + } + crt = crt->droite; + } + } while (crt->key != cle); + } + return crt; +} + +bool arbre_insert(arbre *tree, int cle) { + if (NULL == *tree) { + *tree = calloc(1, sizeof(node)); + (*tree)->key = cle; + } else { + node *nd = position(*tree, cle); + if (cle < nd->key) { + nd->gauche = calloc(1, sizeof(node)); + nd->gauche->key = cle; + } else if (cle > nd->key) { + nd->droite = calloc(1, sizeof(node)); + nd->droite->key = cle; + } else { + return false; + } + } + return true; +} + +static node *parent(arbre tree, node *nd) { + assert(NULL != tree && NULL != nd); + node *parent = NULL; + if (nd != tree) { + node *crt = tree; + int cle = nd->key; + do { + parent = crt; + if (cle < crt->key) { + crt = crt->gauche; + } else if (cle > crt->key) { + crt = crt->droite; + } + } while (crt != nd); + } + return parent; +} + +bool arbre_delete(arbre *tree, int cle) { + node *nd = position(*tree, cle); + + if (NULL == nd || cle != nd->key) { + return false; + } + + // terminal node + if (NULL == nd->gauche && NULL == nd->droite) { + node *nd_parent = parent(*tree, nd); + if (NULL == nd_parent) { // single node tree + *tree = NULL; + } else if (nd == nd_parent->gauche) { + nd_parent->gauche = NULL; + } else if (nd == nd_parent->droite) { + nd_parent->droite = NULL; + } + free(nd); + return true; + } + + if (NULL != nd->gauche) { + node *child = position(nd->gauche, cle); + int val = child->key; + if (NULL == nd->gauche->droite) { + nd->gauche = child->gauche; + free(child); + } else { + bool res = arbre_delete(tree, child->key); + } + nd->key = val; + return true; + } + + if (NULL != nd->droite) { + node *child = position(nd->droite, cle); + int val = child->key; + if (NULL == nd->droite->gauche) { + nd->droite = child->droite; + free(child); + } else { + bool res = arbre_delete(tree, child->key); + } + nd->key = val; + return true; + } + + return false; +} + +void arbre_print(arbre tree, int N) { + if (N <= 0) { + N = 1; + } + if (NULL != tree) { + arbre_print(tree->droite, N + 1); + for (int i = 0; i < N; i++) { + printf(" "); + } + printf("%d\n", tree->key); + arbre_print(tree->gauche, N + 1); + } +} + +bool arbre_search(arbre tree, int cle) { + node *nd = position(tree, cle); + return (NULL != nd && cle == nd->key); +} + diff --git a/source_codes/arbres_binaires/arbre_binaire.h b/source_codes/arbres_binaires/arbre_binaire.h new file mode 100644 index 0000000000000000000000000000000000000000..ca616c6d0803fb5d3550373cdf9dfb56e98b613f --- /dev/null +++ b/source_codes/arbres_binaires/arbre_binaire.h @@ -0,0 +1,21 @@ +#ifndef ARBRE_BINAIRE_H +#define ARBRE_BINAIRE_H + +#include <stdbool.h> + +// Structure pour un arbre binaire +typedef int cle; +typedef struct _node { + cle key; + struct _node *gauche; + struct _node *droite; +} node; +typedef node *arbre; + +// Fonctionnalités pour un arbre binaire ordonné +bool arbre_search(arbre tree, int cle); +bool arbre_insert(arbre *tree, int cle); +bool arbre_delete(arbre *tree, int cle); +void arbre_print(arbre tree, int N); +#endif + diff --git a/source_codes/arbres_binaires/bin_tree.c b/source_codes/arbres_binaires/bin_tree.c new file mode 100644 index 0000000000000000000000000000000000000000..7b2aa0f9240468ca4da0e2655f2cfaafd1477ed6 --- /dev/null +++ b/source_codes/arbres_binaires/bin_tree.c @@ -0,0 +1,148 @@ +#include "bin_tree.h" +#include <assert.h> +#include <math.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +static node *position(arbre tree, cle c) { + node *crt = tree; + if (NULL != crt) { + while (c != crt->key && NULL != crt->child[(c > crt->key)]) { + crt = crt->child[(c > crt->key)]; + } + } + return crt; +} + +bool arbre_is_empty(arbre tree) { + return NULL == tree; +} + +int arbre_depth(arbre tree) { + if (arbre_is_empty(tree)) { + return 0; + } else { + return 1 + + fmax(arbre_depth(tree->child[0]), arbre_depth(tree->child[1])); + } +} + +int arbre_size(arbre tree) { + if (arbre_is_empty(tree)) { + return 0; + } else { + return 1 + arbre_size(tree->child[0]) + arbre_size(tree->child[1]); + } +} + +static node *create_node(int val) { + node *nd = calloc(1, sizeof(node)); + nd->key = val; + return nd; +} + +arbre arbre_insert(arbre tree, cle c) { + if (arbre_is_empty(tree)) { + tree = create_node(c); + } else { + node *nd = position(tree, c); + nd->child[(c > nd->key)] = create_node(c); + } + return tree; +} + +static node *parent(arbre tree, node *nd) { + assert(!arbre_is_empty(tree) && NULL != nd); + node *parent = NULL; + if (nd != tree) { + node *crt = tree; + cle c = nd->key; + do { + parent = crt; + if (c != crt->key) { + crt = crt->child[(c > crt->key)]; + } + } while (crt != nd); + } + return parent; +} + +bool arbre_search(arbre tree, cle c) { + node *nd = position(tree, c); + return (NULL != nd && c == nd->key); +} + +bool arbre_delete(arbre *tree, cle c) { + node *nd = position(*tree, c); + if (NULL == nd || c != nd->key) { + return false; + } + // noeud terminal ou avec 1 enfant + if (arbre_is_empty(nd->child[0]) || arbre_is_empty(nd->child[1])) { + node *nd_parent = parent(*tree, nd); + if (NULL == nd_parent) { // nd est la racine + *tree = nd->child[(NULL != nd->child[1])]; + } else { + nd_parent->child[(nd == nd_parent->child[1])] = + nd->child[(NULL != nd->child[1])]; + } + free(nd); + } else { // noeud interne (2 enfants) + node *next = position(nd->child[1], c); // next a 0 ou 1 enfant + cle tmp = next->key; + bool res = arbre_delete(tree, tmp); + nd->key = tmp; + } + return true; +} + +bool arbre_delete_bis(arbre *tree, cle c) { + node *nd = position(*tree, c); + + if (NULL == nd || c != nd->key) { + return false; + } + + // terminal node + if (arbre_is_empty(nd->child[0]) && arbre_is_empty(nd->child[1])) { + node *nd_parent = parent(*tree, nd); + if (NULL == nd_parent) { // single node tree + *tree = NULL; + } else { + nd_parent->child[(nd == nd_parent->child[1])] = NULL; + } + free(nd); + return true; + } + + for (int ind = 0; ind < 2; ind++) { + if (!arbre_is_empty(nd->child[ind])) { + node *next = position(nd->child[ind], c); + int val = next->key; + if (NULL == nd->child[ind]->child[ind ^ 1]) { + nd->child[ind] = next->child[ind]; + free(next); + } else { + bool res = arbre_delete(tree, next->key); + } + nd->key = val; + return true; + } + } + return false; +} + +void arbre_print(arbre tree, int N) { + if (N <= 0) { + N = 1; + } + if (NULL != tree) { + arbre_print(tree->child[1], N + 1); + for (int i = 0; i < N; i++) { + printf(" "); + } + printf("%d\n", tree->key); + arbre_print(tree->child[0], N + 1); + } +} diff --git a/source_codes/arbres_binaires/bin_tree.h b/source_codes/arbres_binaires/bin_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..3f7fd35fcc237bee5939ccd6016f83ad7f0b6542 --- /dev/null +++ b/source_codes/arbres_binaires/bin_tree.h @@ -0,0 +1,23 @@ +#ifndef BIN_TREE_H +#define BIN_TREE_H + +#include <stdbool.h> + +// Structure pour un arbre binaire +typedef int cle; +typedef struct _node { + cle key; + struct _node *child[2]; +} node; +typedef node *arbre; + +// Fonctionnalités pour un arbre binaire ordonné +bool arbre_is_empty(arbre tree); +bool arbre_search(arbre tree, cle c); +arbre arbre_insert(arbre tree, cle c); +bool arbre_delete(arbre *tree, cle c); +void arbre_print(arbre tree, int N); +int arbre_depth(arbre tree); +int arbre_size(arbre tree); +#endif + diff --git a/source_codes/arbres_binaires/bin_tree_main.c b/source_codes/arbres_binaires/bin_tree_main.c new file mode 100644 index 0000000000000000000000000000000000000000..b5500ddf3bd39e904bacf13501a9a479fb0974e2 --- /dev/null +++ b/source_codes/arbres_binaires/bin_tree_main.c @@ -0,0 +1,25 @@ +#include "bin_tree.h" +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +void main() { + bool b = false; + arbre tree = NULL; + arbre_print(tree, 1); + do { + printf("insert val = "); + int val; + scanf("%d", &val); + b = arbre_insert(tree, val); + arbre_print(tree, 1); + } while (b); + node *nd; + do { + printf("delete val = "); + int val; + scanf("%d", &val); + b = arbre_delete(&tree, val); + arbre_print(tree, 1); + } while (NULL != tree); +} diff --git a/source_codes/arbres_binaires/bin_tree_part.c b/source_codes/arbres_binaires/bin_tree_part.c new file mode 100644 index 0000000000000000000000000000000000000000..dbdd5d5d4516cd9f37d7a458edefb1c840873d01 --- /dev/null +++ b/source_codes/arbres_binaires/bin_tree_part.c @@ -0,0 +1,110 @@ +#include "bin_tree_part.h" +#include <assert.h> +#include <math.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +static node *position(arbre tree, int cle) { + node *crt = tree; + if (NULL != crt) { + while (cle != crt->key && NULL != crt->child[(cle > crt->key)]) { + crt = crt->child[(cle > crt->key)]; + } + } + return crt; +} + +static node *parent(arbre tree, node *nd) { + assert(NULL != tree && NULL != nd); + node *parent = NULL; + int cle = nd->key; + if (nd != tree) { + node *crt = tree; + do { + //à compléter + } while (crt != nd); + } + return parent; +} + +int arbre_depth(arbre tree) { + if (NULL == tree) { + return 0; + } else { + return 1 + + fmax(arbre_depth(tree->child[0]), arbre_depth(tree->child[1])); + } +} + +int arbre_size(arbre tree) { + //à compléter + return 0; +} + +bool arbre_insert(arbre *tree, int cle) { + if (NULL == *tree) { + *tree = calloc(1, sizeof(node)); + (*tree)->key = cle; + } else { + node *nd = position(*tree, cle); + if (cle != nd->key) { + //à compléter + } else { + return false; + } + } + return true; +} + +bool arbre_delete(arbre *tree, int cle) { + node *nd = position(*tree, cle); + if (NULL == nd || cle != nd->key) { + return false; + } + // noeud terminal + if (NULL == nd->child[0] && NULL == nd->child[1]) { + node *nd_parent = parent(*tree, nd); + // à compléter: + // considérer les cas de l'arbre à un seul/plusieurs noeuds + free(nd); + return true; + } + + // noeud interne et récursion + for (int ind = 0; ind < 2; ind++) { + if (NULL != nd->child[ind]) { + node *next = position(nd->child[ind], cle); + int val = next->key; + if (NULL == nd->child[ind]->child[ind ^ 1]) { + nd->child[ind] = next->child[ind]; + free(next); + } else { + bool res = arbre_delete(tree, next->key); + } + nd->key = val; + return true; + } + } + return false; +} + +void arbre_print(arbre tree, int N) { + if (N <= 0) { + N = 1; + } + if (NULL != tree) { + arbre_print(tree->child[1], N + 1); + for (int i = 0; i < N; i++) { + printf(" "); + } + printf("%d\n", tree->key); + arbre_print(tree->child[0], N + 1); + } +} + +bool arbre_search(arbre tree, int cle) { + // à compléter + return true; +} + diff --git a/source_codes/arbres_binaires/bin_tree_part.h b/source_codes/arbres_binaires/bin_tree_part.h new file mode 100644 index 0000000000000000000000000000000000000000..54e846d083756d121aa5f92d22fe05eaabea3542 --- /dev/null +++ b/source_codes/arbres_binaires/bin_tree_part.h @@ -0,0 +1,23 @@ +#ifndef BIN_TREE_H +#define BIN_TREE_H + +#include <stdbool.h> + +// Structure pour un arbre binaire +typedef int cle; +typedef struct _node { + cle key; + struct _node *child[2]; +} node; +typedef node *arbre; + +// Fonctionnalités pour un arbre binaire ordonné +bool arbre_is_empty(arbre tree); +bool arbre_search(arbre tree, cle c); +bool arbre_insert(arbre *tree, cle c); +bool arbre_delete(arbre *tree, cle c); +void arbre_print(arbre tree, int N); +int arbre_depth(arbre tree); +int arbre_size(arbre tree); +#endif + diff --git a/source_codes/arbres_binaires/main.c b/source_codes/arbres_binaires/main.c new file mode 100644 index 0000000000000000000000000000000000000000..6bc9e93e51b4f9bf1c599162ab07dd0a4c0e0fd8 --- /dev/null +++ b/source_codes/arbres_binaires/main.c @@ -0,0 +1,24 @@ +#include "bin_tree.h" +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +void main() { + bool b; + int val; + arbre tree = NULL; + arbre_print(tree, 1); + do { + printf("insert val = "); + scanf("%d", &val); + b = arbre_insert(tree, val); + arbre_print(tree, 1); + } while (b); + node *nd; + do { + printf("delete val = "); + scanf("%d", &val); + b = arbre_delete(&tree, val); + arbre_print(tree, 1); + } while (NULL != tree); +} diff --git a/source_codes/arbres_binaires/tree_search.c b/source_codes/arbres_binaires/tree_search.c new file mode 100644 index 0000000000000000000000000000000000000000..ac4933fbde23d88d58e8f4b54de48e7e782c8ac5 --- /dev/null +++ b/source_codes/arbres_binaires/tree_search.c @@ -0,0 +1,31 @@ +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + +typedef int cle; +typedef struct _node { + cle key; + struct _node *gauche; + struct _node *droite; +} node; +typedef node *arbre; + +arbre search(cle X, arbre tree) { + bool success = false; + arbre courant = tree; + while (NULL != courant && !success) { + if (courant->key > X) { + courant = courant->gauche; + } else if (courant->key < X) { + courant = courant->droite; + } else { + success = true; + } + } + return courant; +} + +void main() { + arbre tree; + arbre t = search(15, tree); +} diff --git a/source_codes/sorting/quicksort/.gitignore b/source_codes/sorting/quicksort/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..b180f6c3fb9bf71cafaccf0e4b07f44ac9bb9b52 --- /dev/null +++ b/source_codes/sorting/quicksort/.gitignore @@ -0,0 +1,2 @@ +quicksort +quicksort_part diff --git a/source_codes/sorting/quicksort/Makefile b/source_codes/sorting/quicksort/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..927fce8eaec2e3f81c8804eb06c2e92709dbbf86 --- /dev/null +++ b/source_codes/sorting/quicksort/Makefile @@ -0,0 +1,21 @@ +CC:=gcc +# SAN:=-fsanitize=address +CFLAGS:=-Wall -Wextra -pedantic -g $(SAN) +LDFLAGS:=-lm $(SAN) + +all: quicksort quicksort_part + +quicksort: quicksort.c + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + @echo $@ >> .gitignore + +quicksort_part: quicksort_part.c + $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) + @echo $@ >> .gitignore + + +.PHONY: clean all + +clean: + rm -f *.o quicksort_part quicksort .gitignore + diff --git a/source_codes/sorting/quicksort/quicksort.c b/source_codes/sorting/quicksort/quicksort.c new file mode 100644 index 0000000000000000000000000000000000000000..af95cb590c2c039a5612fabeb7ef7e5df081f3d2 --- /dev/null +++ b/source_codes/sorting/quicksort/quicksort.c @@ -0,0 +1,83 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <assert.h> + +void print(int size,int tab[size]) { + for (int i=0;i<size;i++) { + printf("%d ",tab[i]); + } +} + +void random_tab(int size,int tab[size],int inf,int sup) { + assert(sup > inf); + for (int i=0;i<size;i++) { + tab[i] = inf+rand()%(sup-inf); + } +} + +void swap(int* p_a,int* p_b) { + int tmp = *p_a; + *p_a = *p_b; + *p_b = tmp; +} + +int partition(int size,int array[size],int first,int last) { + int pivot = array[last]; + int i = first-1,j = last; + do { + do { + i++; + } while (array[i] < pivot && i<j); + do { + j--; + } while(array[j] > pivot && i<j); + if (j>i) { + swap(&array[i],&array[j]); + } + } while (j > i); + swap(&array[i],&array[last]); + return i; +} + +void quicksort(int size,int array[size],int first,int last) { + if (first < last) { + int midpoint = partition(size,array,first,last); + if (first < midpoint-1) { + quicksort(size,array,first,midpoint-1); + } + if (midpoint+1 < last) { + quicksort(size,array,midpoint+1,last); + } + } +} + +void test_ordre(int size,int array[size]) { + for (int i=0;i<size-1;i++) { + if (array[i] > array[i+1]) { + printf("erreur"); + return; + } + } + printf("ok"); +} + +int main(int argc,char** argv) { + if (2 != argc) { + return 1; + } + int size = atoi(argv[1]); + int seed = atoi(argv[2]); + srand(seed); + int* res = malloc(size*sizeof(int)); + for (int k=0;k<20;k++) { + random_tab(size,res,0,100); + print(size,res); + printf("\n"); + quicksort(size,res,0,size-1); + print(size,res); + test_ordre(size,res); + printf("\n================\n"); + } +} + diff --git a/source_codes/sorting/quicksort/quicksort_part.c b/source_codes/sorting/quicksort/quicksort_part.c new file mode 100644 index 0000000000000000000000000000000000000000..67b79b7b790de4e0f71f99465cfc445891c7d621 --- /dev/null +++ b/source_codes/sorting/quicksort/quicksort_part.c @@ -0,0 +1,97 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> + +void print(int size,int tab[size]) { + for (int i=0;i<size;i++) { + printf("%d ",tab[i]); + } + printf("\n"); +} + +void random_tab(int size,int tab[size],int inf,int sup) { + for (int i=0;i<size;i++) { + tab[i] = inf+rand()%(sup-inf); + } +} + +void swap(int* p_a,int* p_b) { + int tmp = *p_a; + *p_a = *p_b; + *p_b = tmp; +} + +// Partition du tableau <array> autour d'une valeur pivot: +// compléter le code +int partition(int size,int array[size],int first,int last) { + int pivot = array[last]; + int i = first-1,j = last; + do { + // à compléter pour <i>: do {...} while (...); + // à compléter pour <j>: do {...} while (...); + // à compléter: échanger cases <i> et <j> du tableau <array> + } while (j > i); + // à compléter: échanger cases <i> et <last> du tableau <array> + return i; +} + +// Tri rapide récursif +void quicksort(int size,int array[size],int first,int last) { + if (first < last) { + int midpoint = partition(size,array,first,last); + if (first < midpoint-1) { + quicksort(size,array,first,midpoint-1); + } + if (midpoint+1 < last) { + quicksort(size,array,midpoint+1,last); + } + } +} + +// Test si le tableau <array> est ordonné croissant +void test_ordre(int size,int array[size]) { + for (int i=0;i<size-1;i++) { + if (array[i] > array[i+1]) { + printf("erreur"); + return; + } + } + printf("ok"); +} + +int main(int argc,char** argv) { + if (2 != argc) { + return 1; + } + int size = atoi(argv[1]); + int seed = atoi(argv[2]); + srand(seed); + int* res = (int*)malloc(size*sizeof(int)); + for (int k=0;k<20;k++) { + random_tab(size,res,0,100); + print(size,res); + quicksort(size,res,0,size-1); + print(size,res); + test_ordre(size,res); + printf("\n================\n"); + } +} + + + + + + + + + + + + + + + + + + +