From e94a7a1565b54c682cfb8b5621e1aba165c45393 Mon Sep 17 00:00:00 2001
From: Orestis <orestis.malaspinas@pm.me>
Date: Thu, 6 Mar 2025 21:48:16 +0100
Subject: [PATCH] updated 2025

---
 slides/cours_16.md | 666 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 666 insertions(+)
 create mode 100644 slides/cours_16.md

diff --git a/slides/cours_16.md b/slides/cours_16.md
new file mode 100644
index 0000000..6286cda
--- /dev/null
+++ b/slides/cours_16.md
@@ -0,0 +1,666 @@
+---
+title: "Arbres binaires"
+date: "2024-03-07"
+---
+
+# Les arbres binaires
+
+\Huge Les arbres binaires
+
+# L'arbre binaire
+
+* Structure de données abstraite,
+* Chaque nœud a au plus deux enfants: gauche et droite,
+* Chaque enfants est un arbre.
+
+## Comment représenteriez vous une telle structure?
+
+. . .
+
+```C
+<R, G, D>
+    R: racine
+    G: sous-arbre gauche
+    D: sous-arbre droite
+```
+
+## Comment cela s'écrirait en C?
+
+. . .
+
+```C
+typedef struct _node {
+    contenu info;
+    struct _node *left, *right;
+} node;
+```
+
+# L'arbre binaire
+
+## Que se passerait-il avec 
+
+```C
+typedef struct _node {
+    int info;
+    struct _node left, right;
+} node;
+```
+
+. . .
+
+* On ne sait pas quelle est la taille de node, on ne peut pas l'allouer!
+
+## Interface minimale
+
+* Qu'y mettriez vous?
+
+. . .
+
+```C 
+NULL              -> arbre (vide)
+<n, arbre, arbre> -> arbre
+visiter(arbre)    -> nœud (la racine de l'arbre)
+gauche(arbre)     -> arbre (sous-arbre de gauche)
+droite(arbre)     -> arbre (sous-arbre de droite)
+```
+
+* Les autres opérations (insertion, parcours, etc) dépendent de ce qu'on stocke
+  dans l'arbre.
+
+# Exemple d'arbre binaire
+
+* Représentez `(c - a * b) * (d + e / f)` à l'aide d'un arbre binaire (matrix)
+
+. . .
+
+::: columns
+
+:::: column
+```{.mermaid format=pdf width=400 loc=figs/}
+graph TD;
+    A[*]-->B[-];
+    B-->C[c];
+    B-->D[*];
+    D-->E[a];
+    D-->F[b];
+    A-->G[+];
+    G-->H[d];
+    G-->I["/"];
+    I-->J[e];
+    I-->K[f];
+```
+::::
+
+
+:::: column
+
+## Remarques
+
+* L'arbre est **hétérogène**: le genre d'info est pas le même sur chaque nœud
+  (opérateur, opérande).
+    * Les feuilles contiennent les opérandes.
+    * Les nœuds internes contiennent les opérateurs.
+
+::::
+
+:::
+
+# L'insertion dans un arbre binaire
+
+* C'est bien joli de pouvoir faire des parcours, recherches, mais si on peut
+  pas construire l'arbre....
+
+## Pour un arbre lexicographique
+
+* Rechercher la position dans l'arbre où insérer.
+* Créer un nœud avec la clé et le rattacher à l'arbre.
+
+# Exemple d'insertions
+
+* Clés uniques pour simplifier.
+* Insertion de 5, 15, 10, 25, 2, -5, 12, 14, 11.
+* Rappel:
+    * Plus petit que la clé courante => gauche,
+    * Plus grand que la clé courante => droite.
+* Faisons le dessins ensemble
+
+```
+
+
+
+
+
+
+
+
+
+```
+
+## Exercice (3min, puis matrix)
+
+* Dessiner l'arbre en insérant 20, 30, 60, 40, 10, 15, 25, -5 
+
+# Pseudo-code d'insertion (1/4)
+
+* Deux parties:
+    * Recherche le parent où se passe l'insertion.
+    * Ajout de l'enfant dans l'arbre.
+
+## Recherche du parent
+
+```
+arbre position(arbre, clé)
+    si est_non_vide(arbre)
+        si clé < clé(arbre)
+            suivant = gauche(arbre)
+        sinon
+            suivant = droite(arbre)
+        tant que clé(arbre) != clé && est_non_vide(suivant)
+            arbre = suivant
+            si clé < clé(arbre)
+                suivant = gauche(arbre)
+            sinon
+                suivant = droite(arbre)
+            
+    retourne arbre
+```
+
+# Pseudo-code d'insertion (2/4)
+
+* Deux parties:
+    * Recherche de la position.
+    * Ajout dans l'arbre.
+
+## Ajout de l'enfant
+
+```
+ajout(arbre, clé)
+    si est_vide(arbre)
+        arbre = nœud(clé)
+    sinon
+        si clé < clé(arbre)
+            gauche(arbre) = nœud(clé)
+        sinon si clé > clé(arbre)
+            droite(arbre) = nœud(clé)
+        sinon
+            retourne
+```
+
+# Code d'insertion en C
+
+## Recherche du parent (ensemble)
+
+. . .
+
+```C
+node *position(node *tree, key_t key) {
+    node * current = tree;
+    if (NULL != current) {
+        node *subtree = key > current->key ? current->right :
+            current->left;
+        while (key != current->key && NULL != subtree) {
+            current = subtree;
+            subtree = key > current->key ? current->right :
+            current->left;
+        }
+    }
+    return current;
+}
+```
+
+# L'insertion (3/4)
+
+* Deux parties:
+    * Recherche de la position.
+    * Ajout dans l'arbre.
+
+## Ajout du fils (pseudo-code)
+
+```
+rien ajout(arbre, clé)
+    si est_vide(arbre)
+        arbre = nœud(clé)
+    sinon
+        arbre = position(arbre, clé)
+        si clé < clé(arbre)
+            gauche(arbre) = nœud(clé)
+        sinon si clé > clé(arbre)
+            droite(arbre) = nœud(clé)
+        sinon
+            retourne
+```
+
+
+
+# L'insertion (4/4)
+
+## Ajout du fils (code)
+
+\scriptsize
+
+* 2 cas: arbre vide ou pas.
+* on retourne un pointeur vers le nœud ajouté (ou `NULL`)
+
+. . .
+
+```C
+node *add_key(node **tree, key_t key) {
+    node *new_node = calloc(1, sizeof(*new_node));
+    new_node->key = key;
+    if (NULL == *tree) {
+        *tree = new_node;
+    } else {
+        node * subtree = position(*tree, key);
+        if (key == subtree->key) {
+            return NULL;
+        } else {
+            if (key > subtree->key) {
+                subtree->right = new_node;
+            } else {
+                subtree->left = new_node;
+            }
+        }
+    }
+    return new_node;
+}
+```
+
+# Parcours d'arbres binaires
+
+* Appliquer une opération à tous les nœuds de l'arbre,
+* Nécessité de **parcourir** l'arbre,
+* Utiliser uniquement l'interface: visiter, gauche,
+  droite.
+
+## Une idée de comment parcourir cet arbre?
+
+* 3 parcours (R: Racine, G: sous-arbre gauche, D: sous-arbre droit):
+
+
+::: columns
+
+:::: column
+```{.mermaid format=pdf width=400 loc=figs/}
+graph TD;
+    A[*]-->B[-];
+    B-->C[c];
+    B-->D[*];
+    D-->E[a];
+    D-->F[b];
+    A-->G[+];
+    G-->H[d];
+    G-->I["/"];
+    I-->J[e];
+    I-->K[f];
+```
+::::
+
+:::: column
+
+1. Parcours **préfixe** (R, G, D),
+2. Parcours **infixe** (G, R, D),
+3. Parcours **postfixe** (G, D, R).
+
+::::
+
+:::
+
+# Le parcours infixe (G, R, D)
+
+* Gauche, Racine, Droite:
+    1. On descend dans l'arbre de gauche tant qu'il est pas vide,
+    2. On visite la racine du sous arbre,
+    3. On descend dans le sous-arbre de droite (s'il est pas vide),
+    4. On recommence.
+
+. . .
+
+## Incompréhensible?
+
+* La récursivité c'est la vie.
+    
+```
+parcours_infixe(arbre a)
+    si est_pas_vide(gauche(a))
+       parcours_infixe(gauche(a))
+    visiter(A)
+    si est_pas_vide(droite(A))
+       parcours_infixe(droite(A))
+```
+
+# Graphiquement (dessinons)
+
+::: columns
+
+:::: column
+```{.mermaid format=pdf width=400 loc=figs/}
+graph TD;
+    A[*]-->B[-];
+    B-->C[c];
+    B-->D[*];
+    D-->E[a];
+    D-->F[b];
+    A-->G[+];
+    G-->H[d];
+    G-->I["/"];
+    I-->J[e];
+    I-->K[f];
+```
+::::
+
+:::: column
+
+```
+parcours_infixe(arbre a)
+    si est_pas_vide(gauche(a))
+       parcours_infixe(gauche(a))
+    visiter(A)
+    si est_pas_vide(droite(A))
+       parcours_infixe(droite(A))
+```
+
+::::
+
+:::
+
+
+# Graphiquement (`mermaid` c'est super)
+
+::: columns
+
+:::: column
+```{.mermaid format=pdf width=400 loc=figs/}
+graph TD;
+    A[*]-->B[-];
+    A[*]-.->|1|B[-];
+    B-->C[c];
+    B-.->|2|C[c];
+    C-.->|3|B;
+    B-->D[*];
+    B-.->|4|D;
+    D-->E[a];
+    D-.->|5|E;
+    E-.->|6|D;
+    D-->F[b];
+    D-.->|7|F;
+    F-.->|8|A;
+    A-->G[+];
+    A-.->|9|G;
+    G-->H[d];
+    G-.->|10|H;
+    H-.->|11|G;
+    G-->I["/"];
+    G-.->|12|I;
+    I-->J[e];
+    I-.->|13|J;
+    J-.->|14|I;
+    I-->K[f];
+    I-.->|15|K;
+```
+::::
+
+:::: column
+
+```
+parcours_infixe(arbre a)
+    si est_pas_vide(gauche(a))
+       parcours_infixe(gauche(a))
+    visiter(A)
+    si est_pas_vide(droite(A))
+       parcours_infixe(droite(A))
+```
+
+## Remarque 
+
+Le nœud est visité à la **remontée**.
+
+## Résultat
+
+```
+c - a * b * d + e / f
+```
+
+::::
+
+:::
+
+# Et en C?
+
+## Live code
+
+\footnotesize
+
+. . .
+
+```C
+typedef int data;
+typedef struct _node {
+    data info;
+    struct _node* left;
+    struct _node* right;
+} node;
+void tree_print(node *tree, int n) {
+    if (NULL != tree) {
+        tree_print(tree->left, n+1);
+        for (int i = 0; i < n; i++) {
+            printf(" ");
+        }
+        printf("%d\n", tree->info);
+        tree_print(tree->right, n+1);
+    }
+}
+```
+
+# Question
+
+## Avez-vous compris le fonctionnement?
+
+. . .
+
+## Vous en êtes sûr·e·s?
+
+. . .
+
+## OK, alors deux exercices:
+
+1. Écrire le pseudo-code pour le parcours R, G, D (matrix).
+2. Écrire le pseudo-code pour la parcours G, D, R (matrix),
+
+## Rappel
+
+```
+parcours_infixe(arbre a)
+    si est_pas_vide(gauche(a))
+       parcours_infixe(gauche(a))
+    visiter(a)
+    si est_pas_vide(droite(a))
+       parcours_infixe(droite(a))
+```
+
+# Correction
+
+\footnotesize
+
+* Les deux parcours sont des modifications **triviales**[^2] de l'algorithme
+  infixe.
+
+## Le parcours postfixe
+
+```python
+parcours_postfixe(arbre a)
+    si est_pas_vide(gauche(a))
+       parcours_postfixe(gauche(a))
+    si est_pas_vide(droite(a))
+       parcours_postfixe(droite(a))
+    visiter(a)
+```
+
+## Le parcours préfixe
+
+```python
+parcours_préfixe(arbre a)
+    visiter(a)
+    si est_pas_vide(gauche(a))
+        parcours_préfixe(gauche(a))
+    si est_pas_vide(droite(a))
+        parcours_préfixe(droite(a))
+```
+
+. . .
+
+**Attention:** L'implémentation de ces fonctions en C sont **à faire** en
+exercice (inspirez vous de ce qu'on a fait avant)!
+
+# Exercice: parcours
+
+## Comment imprimer l'arbre ci-dessous?
+
+```
+                        f
+                /
+                        e
+        +
+                d
+*
+                c
+        -
+                        b
+                *
+                        a
+```
+
+. . .
+
+## Bravo vous avez trouvé! 
+
+* Il s'agissait du parcours D, R, G.
+
+# Implémentation
+
+## Vous avez 5 min pour implémenter cette fonction et la poster sur matrix!
+
+. . .
+
+```C 
+void pretty_print(node *tree, int n) {
+    if (NULL != tree) {
+        pretty_print(tree->right, n+1);
+        for (int i = 0; i < n; ++i) {
+            printf(" ");
+        }
+        printf("%d\n", tree->info);
+        pretty_print(tree->left, n+1);
+    }
+}
+```
+
+# Exercice supplémentaire (sans corrigé)
+
+Écrire le code de la fonction 
+
+```C
+int depth(node *t);
+```
+
+qui retourne la profondeur maximale d'un arbre.
+
+Indice: la profondeur à chaque niveau peut-être calculée à partir du niveau des
+sous-arbres de gauche et de droite.
+
+# La recherche dans un arbre binaire
+
+* Les arbres binaires peuvent retrouver une information très rapidement.
+* À quelle complexité? À quelle condition?
+
+. . .
+
+## Condition
+
+* Le contenu de l'arbre est **ordonné** (il y a une relation d'ordre (`<`, `>`
+  entre les éléments).
+
+## Complexité
+
+* La profondeur de l'arbre (ou le $\mathcal{O}(\log_2(N))$)
+
+. . .
+
+## Exemple: les arbres lexicographiques
+
+* Chaque nœud contient une information de type ordonné, la **clé**,
+* Par construction, pour chaque nœud $N$:
+    * Toutes clé du sous-arbre à gauche de $N$ sont inférieurs à la clé de $N$.
+    * Toutes clé du sous-arbre à droite de $N$ sont inférieurs à la clé de $N$.
+
+# Algorithme de recherche
+
+* Retourner le nœud si la clé est trouvée dans l'arbre.
+
+```python
+arbre recherche(clé, arbre)
+    tante_que est_non_vide(arbre)
+        si clé < clé(arbre)
+            arbre = gauche(arbre)
+        sinon si clé > clé(arbre)
+            arbre = droite(arbre)
+        sinon
+            retourne arbre
+    retourne NULL
+```
+
+# Algorithme de recherche, implémentation (live)
+
+\footnotesize
+
+. . .
+
+```C 
+typedef int key_t;
+typedef struct _node {
+    key_t key;
+    struct _node* left;
+    struct _node* right;
+} node;
+node *search(key_t key, node *tree) {
+    node *current = tree;
+    while (NULL != current) {
+        if (current->key > X) {
+            current = current->gauche;
+        } else if (current->key < X){
+            current = current->droite;
+        } else {
+            return current;
+        }
+    }
+    return NULL;
+}
+```
+
+# Exercice (5-10min)
+
+Écrire le code de la fonction
+
+```C 
+int tree_size(node *tree);
+```
+
+qui retourne le nombre total de nœuds d'un arbre et poster le résultat sur
+matrix.
+
+Indication: la taille, est 1 + le nombre de nœuds du sous-arbre de gauche
+additionné au nombre de nœuds dans le sous-arbre de droite.
+
+. . .
+
+```C
+int arbre_size(node *tree) {
+    if (NULL == tree) {
+        return 0;
+    } else {   
+        return 1 + tree_size(tree->left) 
+            + tree_size(tree->right);
+    }
+}
+```
+
+[^2]: Copyright cours de mathématiques pendant trop d'années.
-- 
GitLab