From 0ef352e3c3391ae35c5e532ec559451da066c8c5 Mon Sep 17 00:00:00 2001
From: Orestis <orestis.malaspinas@pm.me>
Date: Sun, 5 Nov 2023 21:54:28 +0100
Subject: [PATCH] maj 2023 started

---
 slides/cours_6.md | 347 ------------------
 slides/cours_7.md | 874 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 874 insertions(+), 347 deletions(-)
 create mode 100644 slides/cours_7.md

diff --git a/slides/cours_6.md b/slides/cours_6.md
index 311016a..c8144c8 100644
--- a/slides/cours_6.md
+++ b/slides/cours_6.md
@@ -597,350 +597,3 @@ int fib_imp(int n) {
 }
 ```
 
-# Exponentiation rapide ou indienne (1/4)
-
-## But: Calculer $x^n$
-
-* Quel est l'algorithmie le plus simple que vous pouvez imaginer?
-
-. . .
-
-```C
-int pow(int x, int n) {
-    if (0 == n) {
-        return 1;
-    }
-    for (int i = 1; i < n; ++i) {
-        x = x * x; // x *= x
-    }
-    return x;
-}
-```
-
-* Combien de multiplication et d'assignations en fonction de `n`?
-
-. . .
-
-* `n` assignations et `n` multiplications.
-
-# Exponentiation rapide ou indienne (2/4)
-
-* Proposez un algorithme naïf et récursif
-
-. . .
-
-```C
-int pow(x, n) {
-    if (n != 0) {
-        return x * pow(x, n-1);
-    } else {
-        return 1;
-    }
-}
-```
-
-# Exponentiation rapide ou indienne (3/4)
-
-## Exponentiation rapide ou indienne de $x^n$
-
-* Écrivons $n=\sum_{i=0}^{d-1}b_i 2^i,\ b_i=\{0,1\}$ (écriture binaire sur $d$ bits, avec
-$d\sim\log_2(n)$).
-* 
-$$
-x^n={x^{2^0}}^{b_0}\cdot {x^{2^1}}^{b_1}\cdots {x^{2^{d-1}}}^{b_{d-1}}.
-$$
-* On a besoin de $d$ calculs pour les $x^{2^i}$.
-* On a besoin de $d$ calculs pour évaluer les produits de tous les termes.
-
-## Combien de calculs en terme de $n$?
-
-. . .
-
-* $n$ est représenté en binaire avec $d$ bits $\Rightarrow d\sim\log_2(n)$.
-* il y a $2\log_2(n)\sim \log_2(n)$ calculs.
-
-# Exponentiation rapide ou indienne (4/4)
-
-## Le vrai algorithme
-
-* Si n est pair: calculer $\left(x^{n/2}\right)^2$,
-* Si n est impair: calculer $x \cdot \left(x^{(n-1)/2}\right)^2$.
-
-## Exercice: écrire l'algorithme récursif correspondant
-
-. . .
-
-```C
-double pow(double x, int n) {
-    if (1 == n) {
-        return x;
-    } else if (n % 2 == 0) {
-        return pow(x, n / 2) * pow(x, n/2);
-    } else {
-        return x * pow(x, (n-1));
-    }
-}
-```
-
-
-# Efficacité d'un algorithmique
-
-Comment mesurer l'efficacité d'un algorithme?
-
-. . .
-
-* Mesurer le temps CPU,
-* Mesurer le temps d'accès à la mémoire,
-* Mesurer la place prise mémoire,
-
-. . .
-
-Dépendant du **matériel**, du **compilateur**, des **options de compilation**, etc!
-
-## Mesure du temps CPU
-
-```C
-#include <time.h>
-struct timespec tstart={0,0}, tend={0,0};
-clock_gettime(CLOCK_MONOTONIC, &tstart);
-// some computation
-clock_gettime(CLOCK_MONOTONIC, &tend);
-printf("computation about %.5f seconds\n",
-       ((double)tend.tv_sec + 1e-9*tend.tv_nsec) - 
-       ((double)tstart.tv_sec + 1e-9*tstart.tv_nsec));
-```
-
-# Programme simple: mesure du temps CPU
-
-## Preuve sur un [petit exemple](../source_codes/complexity/sum.c)
-
-```bash
-source_codes/complexity$ make bench
-RUN ONCE -O0
-the computation took about 0.00836 seconds
-RUN ONCE -O3
-the computation took about 0.00203 seconds
-RUN THOUSAND TIMES -O0
-the computation took about 0.00363 seconds
-RUN THOUSAND TIMES -O3
-the computation took about 0.00046 seconds
-```
-
-Et sur votre machine les résultats seront **différents**.
-
-. . .
-
-## Conclusion
-
-* Nécessité d'avoir une mesure indépendante du/de la
-  matériel/compilateur/façon de mesurer/météo.
-
-# Analyse de complexité algorithmique (1/4)
-
-* On analyse le **temps** pris par un algorithme en fonction de la **taille de
-  l'entrée**.
-
-## Exemple: recherche d'un élément dans une liste triée de taille N
-
-```C
-int sorted_list[N];
-bool in_list = is_present(N, sorted_list, elem);
-```
-
-* Plus `N` est grand, plus l'algorithme prend de temps sauf si...
-
-. . .
-
-* l'élément est le premier de la liste (ou à une position toujours la même).
-* ce genre de cas pathologique ne rentre pas en ligne de compte.
-
-# Analyse de complexité algorithmique (2/4)
-
-## Recherche linéaire
-
-```C
-bool is_present(int n, int tab[], int elem) {
-    for (int i = 0; i < n; ++i) {
-        if (tab[i] == elem) {
-            return true;
-        } else if (elem < tab[i]) {
-            return false;
-        }
-    }
-    return false;
-}
-```
-
-* Dans le **meilleurs des cas** il faut `1` comparaison.
-* Dans le **pire des cas** (élément absent p.ex.) il faut `n` comparaisons.
-
-. . .
-
-La **complexité algorithmique** est proportionnelle à `N`: on double la taille
-du tableau $\Rightarrow$ on double le temps pris par l'algorithme.
-
-# Analyse de complexité algorithmique (3/4)
-
-## Recherche dichotomique
-
-```C
-bool is_present_binary_search(int n, int tab[], int elem) {
-    int left  = 0;
-    int right = n - 1;
-    while (left <= right) {
-        int mid = (right + left) / 2;
-        if (tab[mid] < elem) {
-            left = mid + 1;
-        } else if (tab[mid] > elem) {
-            right = mid - 1;
-        } else {
-            return true;
-        }
-    }
-    return false;
-}
-```
-
-# Analyse de complexité algorithmique (4/4)
-
-## Recherche dichotomique
-
-![Source: [Wikipédia](https://upload.wikimedia.org/wikipedia/commons/a/aa/Binary_search_complexity.svg)](figs/Binary_search_complexity.svg){width=80%}
-
-. . .
-
-* Dans le **meilleurs de cas** il faut `1` comparaison.
-* Dans le **pire des cas** il faut $\log_2(N)+1$ comparaisons
-
-. . .
-
-## Linéaire vs dichotomique
-
-* $N$ vs $\log_2(N)$ comparaisons logiques.
-* Pour $N=1000000$: `1000000` vs `21` comparaisons.
-
-# Notation pour la complexité
-
-## Constante de proportionnalité
-
-* Pour la recherche linéaire ou dichotomique, on a des algorithmes qui sont $\sim N$ ou $\sim \log_2(N)$
-* Qu'est-ce que cela veut dire?
-
-. . .
-
-* Temps de calcul est $t=C\cdot N$ (où $C$ est le temps pris pour une comparaisons sur une machine/compilateur donné)
-* La complexité ne dépend pas de $C$.
-
-## Le $\mathcal{O}$ de Leibnitz
-
-* Pour noter la complexité d'un algorithme on utilise le symbole $\mathcal{O}$ (ou "grand Ô de").
-* Les complexités les plus couramment rencontrées sont
-
-. . .
-
-$$
-\mathcal{O}(1),\quad \mathcal{O}(\log(N)),\quad \mathcal{O}(N),\quad
-\mathcal{O}(\log(N)\cdot N), \quad \mathcal{O}(N^2), \quad
-\mathcal{O}(N^3).
-$$
-
-# Ordres de grandeur
-
-\begin{table}[!h]  
-\begin{center} 
-\caption{Valeurs approximatives de quelques fonctions usuelles de complexité.} 
-\medskip 
-\begin{tabular}{|c|c|c|c|c|} 
-\hline 
-$\log_2(N)$ & $\sqrt{N}$      & $N$    & $N\log_2(N)$    & $N^2$     \\ 
-\hline\hline 
-$3$         & $3$             & $10$   & $30$            & $10^2$    \\ 
-\hline 
-$6$         & $10$            & $10^2$ & $6\cdot 10^2$   & $10^4$    \\ 
-\hline 
-$9$         & $31$            & $10^3$ & $9\cdot 10^3$   & $10^6$    \\ 
-\hline 
-$13$        & $10^2$          & $10^4$ & $1.3\cdot 10^5$ & $10^8$    \\ 
-\hline 
-$16$        & $3.1\cdot 10^2$ & $10^5$ & $1.6\cdot 10^6$ & $10^{10}$ \\ 
-\hline 
-$19$        & $10^3$          & $10^6$ & $1.9\cdot 10^7$ & $10^{12}$ \\ 
-\hline 
-\end{tabular} 
-\end{center} 
-\end{table} 
-
-
-# Quelques exercices (1/3)
-
-## Complexité de l'algorithme de test de primalité naïf?
-
-```C
-for (i = 2; i < sqrt(N); ++i) {
-    if (N % i == 0) {
-        return false;
-    }
-}
-return true;
-```
-
-. . .
-
-## Réponse 
-
-$$
-\mathcal{O}(\sqrt{N}).
-$$
-
-# Quelques exercices (2/3)
-
-## Complexité de trouver le minimum d'un tableau?
-
-```C
-int min = MAX;
-for (i = 0; i < N; ++i) {
-    if (tab[i] < min) {
-        min = tab[i];
-    }
-}
-return min;
-```
-
-. . .
-
-## Réponse 
-
-$$
-\mathcal{O}(N).
-$$
-
-# Quelques exercices (3/3)
-
-## Complexité du tri par sélection?
-
-```C
-int ind = 0
-while (ind < SIZE-1) {
-    min = find_min(tab[ind:SIZE]);
-    swap(min, tab[ind]);
-    ind += 1
-}
-```
-
-. . .
-
-## Réponse
-
-### `min = find_min`
-
-$$
-(N-1)+(N-2)+...+2+1=\sum_{i=1}^{N-1}i=N\cdot(N-1)/2=\mathcal{O}(N^2).
-$$
-
-## Finalement
-
-$$
-\mathcal{O}(N^2\mbox{ comparaisons}) + \mathcal{O}(N\mbox{swaps})=\mathcal{O}(N^2).
-$$
-
-
diff --git a/slides/cours_7.md b/slides/cours_7.md
new file mode 100644
index 0000000..12e9665
--- /dev/null
+++ b/slides/cours_7.md
@@ -0,0 +1,874 @@
+---
+title: "Récursion et tris"
+date: "2022-11-16"
+---
+
+# Exponentiation rapide ou indienne (1/4)
+
+## But: Calculer $x^n$
+
+* Quel est l'algorithmie le plus simple que vous pouvez imaginer?
+
+. . .
+
+```C
+int pow(int x, int n) {
+    if (0 == n) {
+        return 1;
+    }
+    for (int i = 1; i < n; ++i) {
+        x = x * x; // x *= x
+    }
+    return x;
+}
+```
+
+* Combien de multiplication et d'assignations en fonction de `n`?
+
+. . .
+
+* `n` assignations et `n` multiplications.
+
+# Exponentiation rapide ou indienne (2/4)
+
+* Proposez un algorithme naïf et récursif
+
+. . .
+
+```C
+int pow(x, n) {
+    if (n != 0) {
+        return x * pow(x, n-1);
+    } else {
+        return 1;
+    }
+}
+```
+
+# Exponentiation rapide ou indienne (3/4)
+
+## Exponentiation rapide ou indienne de $x^n$
+
+* Écrivons $n=\sum_{i=0}^{d-1}b_i 2^i,\ b_i=\{0,1\}$ (écriture binaire sur $d$ bits, avec
+$d\sim\log_2(n)$).
+* 
+$$
+x^n={x^{2^0}}^{b_0}\cdot {x^{2^1}}^{b_1}\cdots {x^{2^{d-1}}}^{b_{d-1}}.
+$$
+* On a besoin de $d$ calculs pour les $x^{2^i}$.
+* On a besoin de $d$ calculs pour évaluer les produits de tous les termes.
+
+## Combien de calculs en terme de $n$?
+
+. . .
+
+* $n$ est représenté en binaire avec $d$ bits $\Rightarrow d\sim\log_2(n)$.
+* il y a $2\log_2(n)\sim \log_2(n)$ calculs.
+
+# Exponentiation rapide ou indienne (4/4)
+
+## Le vrai algorithme
+
+* Si n est pair: calculer $\left(x^{n/2}\right)^2$,
+* Si n est impair: calculer $x \cdot \left(x^{(n-1)/2}\right)^2$.
+
+## Exercice: écrire l'algorithme récursif correspondant
+
+. . .
+
+```C
+double pow(double x, int n) {
+    if (1 == n) {
+        return x;
+    } else if (n % 2 == 0) {
+        return pow(x, n / 2) * pow(x, n/2);
+    } else {
+        return x * pow(x, (n-1));
+    }
+}
+```
+
+# Tri rapide ou quicksort (1/8)
+
+## Idée: algorithme `diviser pour régner` (`divide-and-conquer`)
+
+* Diviser: découper un problème en sous problèmes;
+* Régner: résoudre les sous-problèmes (souvent récursivement);
+* Combiner: à partir des sous problèmes résolu, calculer la solution.
+
+## Le pivot
+
+* Trouver le **pivot**, un élément qui divise le tableau en 2, tels que:
+    1. Éléments à gauche sont **plus petits** que le pivot.
+    2. Élements à droite sont **plus grands** que le pivot.
+
+# Tri rapide ou quicksort (2/8)
+
+## Algorithme `quicksort(tableau)`
+
+1. Choisir le pivot et l'amener à sa place:
+    * Les éléments à gauche sont plus petits que le pivot.
+    * Les éléments à droite sont plus grand que le pivot.
+2. `quicksort(tableau_gauche)` en omettant le pivot.
+3. `quicksort(tableau_droite)` en omettant le pivot.
+4. S'il y a moins de deux éléments dans le tableau, le tableau est trié.
+
+. . .
+
+Compris?
+
+. . .
+
+Non c'est normal, faisons un exemple.
+
+# Tri rapide ou quicksort (3/8)
+
+\footnotesize
+
+Deux variables sont primordiales:
+
+```C
+entier ind_min, ind_max; // les indices min/max des tableaux à trier
+```
+
+![Un exemple de quicksort.](figs/quicksort.svg)
+
+# Tri rapide ou quicksort (4/8)
+
+\footnotesize
+
+Deux variables sont primordiales:
+
+```C
+entier ind_min, ind_max; // les indices min/max des tableaux à trier
+```
+
+## Pseudocode: quicksort
+
+```python
+rien quicksort(entier tableau[], entier ind_min, entier ind_max)
+    si (longueur(tab) > 1)
+        ind_pivot = partition(tableau, ind_min, ind_max)
+        si (longueur(tableau[ind_min:ind_pivot-1]) != 0)
+            quicksort(tableau, ind_min, pivot_ind - 1)
+        si (longueur(tableau[ind_pivot+1:ind_max-1]) != 0)
+            quicksort(tableau, ind_pivot + 1, ind_max)
+```
+
+# Tri rapide ou quicksort (5/8)
+
+\footnotesize
+
+## Pseudocode: partition
+
+```C
+entier partition(entier tableau[], entier ind_min, entier ind_max)
+    pivot = tableau[ind_max] // choix arbitraire
+    i = ind_min
+    j = ind_max-1
+    tant que i < j:
+        en remontant i trouver le premier élément > pivot
+        en descendant j trouver le premier élément < pivot
+        échanger(tableau[i], tableau[j])
+        // les plus grands à droite
+        // mettre les plus petits à gauche
+    
+    // on met le pivot "au milieu"
+    échanger(tableau[i], tableau[ind_max])    
+    retourne i // on retourne l'indice pivot
+```
+
+# Tri rapide ou quicksort (6/8)
+
+## Exercice: implémenter les fonctions `quicksort` et `partition`
+
+. . .
+
+```C
+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);
+        }
+    }
+}
+```
+
+
+# Tri rapide ou quicksort (7/8)
+
+\footnotesize
+
+## Exercice: implémenter les fonctions `quicksort` et `partition`
+
+```C 
+int partition(int size, int array[size], int first, int last) {
+    int pivot = array[last];
+    int i = first - 1, j = last;
+    do {
+        do {
+            i += 1;
+        } while (array[i] < pivot && i < j);
+        do {
+            j -= 1;
+        } while (array[j] > pivot && i < j);
+        if (j > i) {
+            swap(&array[i], &array[j]);
+        }
+    } while (j > i);
+    swap(&array[i], &array[last]);
+    return i;
+}
+```
+
+# Tri rapide ou quicksort (8/8)
+
+## Quelle est la complexité du tri rapide?
+
+. . .
+
+* Pire des cas plus: $\mathcal{O}(N^2)$
+    * Quand le pivot sépare toujours le tableau de façon déséquilibrée ($N-1$
+      éléments d'un côté $1$ de l'autre).
+    * $N$ boucles et $N$ comparaisons $\Rightarrow N^2$.
+* Meilleur des cas (toujours le meilleur pivot): $\mathcal{O}(N\cdot \log_2(N))$.
+    * Chaque fois le tableau est séparé en $2$ parties égales.
+    * On a $\log_2(N)$ partitions, et $N$ boucles $\Rightarrow N\cdot
+      \log_2(N)$.
+* En moyenne: $\mathcal{O}(N\cdot \log_2(N))$.
+
+# L'algorithme à la main
+
+## Exercice *sur papier*
+
+* Trier par tri rapide le tableau `[5, -2, 1, 3, 10, 15, 7, 4]`
+
+```C
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+
+# Tri à bulle (1/4)
+
+## Algorithme
+
+* Parcours du tableau et comparaison des éléments consécutifs:
+    - Si deux éléments consécutifs ne sont pas dans l'ordre, ils sont échangés.
+* On recommence depuis le début du tableau jusqu'à avoir plus d'échanges à
+  faire.
+
+## Que peut-on dire sur le dernier élément du tableau après un parcours?
+
+. . .
+
+* Le plus grand élément est **à la fin** du tableau.
+    * Plus besoin de le traiter.
+* A chaque parcours on s'arrête un élément plus tôt.
+
+# Tri à bulle (2/4)
+
+## Exemple
+
+![Tri à bulles d'un tableau d'entiers](figs/tri_bulles.svg)
+
+
+# Tri à bulle (3/4)
+
+## Exercice: écrire l'algorithme (poster le résultat sur matrix)
+
+. . .
+
+```C
+rien tri_a_bulles(entier tableau[])
+    pour i de longueur(tableau)-1 à 1:
+        trié = vrai
+        pour j de 0 à i-1:
+            si (tableau[j] > tableau[j+1])
+                échanger(array[j], array[j+1])
+                trié = faux
+        
+        si trié
+            retourner
+```
+
+# Tri à bulle (4/4)
+
+## Quelle est la complexité du tri à bulles?
+
+. . .
+
+* Dans le meilleurs des cas:
+    * Le tableau est déjà trié: $\mathcal{O}(N)$ comparaisons.
+* Dans le pire des cas, $N\cdot (N-1)/2\sim\mathcal{O}(N^2)$:
+$$
+\sum_{i=1}^{N-1}i\mbox{ comparaison et }3\sum_{i=1}^{N-1}i \mbox{ affectations
+(swap)}\Rightarrow \mathcal{O}(N^2).
+$$
+* En moyenne, $\mathcal{O}(N^2)$ ($N^2/2$ comparaisons).
+
+# L'algorithme à la main
+
+## Exercice *sur papier*
+
+* Trier par tri à bulles le tableau `[5, -2, 1, 3, 10, 15, 7, 4]`
+
+```C
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+
+# Efficacité d'un algorithmique
+
+Comment mesurer l'efficacité d'un algorithme?
+
+. . .
+
+* Mesurer le temps CPU,
+* Mesurer le temps d'accès à la mémoire,
+* Mesurer la place prise mémoire,
+
+. . .
+
+Dépendant du **matériel**, du **compilateur**, des **options de compilation**, etc!
+
+## Mesure du temps CPU
+
+```C
+#include <time.h>
+struct timespec tstart={0,0}, tend={0,0};
+clock_gettime(CLOCK_MONOTONIC, &tstart);
+// some computation
+clock_gettime(CLOCK_MONOTONIC, &tend);
+printf("computation about %.5f seconds\n",
+       ((double)tend.tv_sec + 1e-9*tend.tv_nsec) - 
+       ((double)tstart.tv_sec + 1e-9*tstart.tv_nsec));
+```
+
+# Programme simple: mesure du temps CPU
+
+## Preuve sur un [petit exemple](../source_codes/complexity/sum.c)
+
+```bash
+source_codes/complexity$ make bench
+RUN ONCE -O0
+the computation took about 0.00836 seconds
+RUN ONCE -O3
+the computation took about 0.00203 seconds
+RUN THOUSAND TIMES -O0
+the computation took about 0.00363 seconds
+RUN THOUSAND TIMES -O3
+the computation took about 0.00046 seconds
+```
+
+Et sur votre machine les résultats seront **différents**.
+
+. . .
+
+## Conclusion
+
+* Nécessité d'avoir une mesure indépendante du/de la
+  matériel/compilateur/façon de mesurer/météo.
+
+# Analyse de complexité algorithmique (1/4)
+
+* On analyse le **temps** pris par un algorithme en fonction de la **taille de
+  l'entrée**.
+
+## Exemple: recherche d'un élément dans une liste triée de taille N
+
+```C
+int sorted_list[N];
+bool in_list = is_present(N, sorted_list, elem);
+```
+
+* Plus `N` est grand, plus l'algorithme prend de temps sauf si...
+
+. . .
+
+* l'élément est le premier de la liste (ou à une position toujours la même).
+* ce genre de cas pathologique ne rentre pas en ligne de compte.
+
+# Analyse de complexité algorithmique (2/4)
+
+## Recherche linéaire
+
+```C
+bool is_present(int n, int tab[], int elem) {
+    for (int i = 0; i < n; ++i) {
+        if (tab[i] == elem) {
+            return true;
+        } else if (elem < tab[i]) {
+            return false;
+        }
+    }
+    return false;
+}
+```
+
+* Dans le **meilleurs des cas** il faut `1` comparaison.
+* Dans le **pire des cas** (élément absent p.ex.) il faut `n` comparaisons.
+
+. . .
+
+La **complexité algorithmique** est proportionnelle à `N`: on double la taille
+du tableau $\Rightarrow$ on double le temps pris par l'algorithme.
+
+# Analyse de complexité algorithmique (3/4)
+
+## Recherche dichotomique
+
+```C
+bool is_present_binary_search(int n, int tab[], int elem) {
+    int left  = 0;
+    int right = n - 1;
+    while (left <= right) {
+        int mid = (right + left) / 2;
+        if (tab[mid] < elem) {
+            left = mid + 1;
+        } else if (tab[mid] > elem) {
+            right = mid - 1;
+        } else {
+            return true;
+        }
+    }
+    return false;
+}
+```
+
+# Analyse de complexité algorithmique (4/4)
+
+## Recherche dichotomique
+
+![Source: [Wikipédia](https://upload.wikimedia.org/wikipedia/commons/a/aa/Binary_search_complexity.svg)](figs/Binary_search_complexity.svg){width=80%}
+
+. . .
+
+* Dans le **meilleurs de cas** il faut `1` comparaison.
+* Dans le **pire des cas** il faut $\log_2(N)+1$ comparaisons
+
+. . .
+
+## Linéaire vs dichotomique
+
+* $N$ vs $\log_2(N)$ comparaisons logiques.
+* Pour $N=1000000$: `1000000` vs `21` comparaisons.
+
+# Notation pour la complexité
+
+## Constante de proportionnalité
+
+* Pour la recherche linéaire ou dichotomique, on a des algorithmes qui sont $\sim N$ ou $\sim \log_2(N)$
+* Qu'est-ce que cela veut dire?
+
+. . .
+
+* Temps de calcul est $t=C\cdot N$ (où $C$ est le temps pris pour une comparaisons sur une machine/compilateur donné)
+* La complexité ne dépend pas de $C$.
+
+## Le $\mathcal{O}$ de Leibnitz
+
+* Pour noter la complexité d'un algorithme on utilise le symbole $\mathcal{O}$ (ou "grand Ô de").
+* Les complexités les plus couramment rencontrées sont
+
+. . .
+
+$$
+\mathcal{O}(1),\quad \mathcal{O}(\log(N)),\quad \mathcal{O}(N),\quad
+\mathcal{O}(\log(N)\cdot N), \quad \mathcal{O}(N^2), \quad
+\mathcal{O}(N^3).
+$$
+
+# Ordres de grandeur
+
+\begin{table}[!h]  
+\begin{center} 
+\caption{Valeurs approximatives de quelques fonctions usuelles de complexité.} 
+\medskip 
+\begin{tabular}{|c|c|c|c|c|} 
+\hline 
+$\log_2(N)$ & $\sqrt{N}$      & $N$    & $N\log_2(N)$    & $N^2$     \\ 
+\hline\hline 
+$3$         & $3$             & $10$   & $30$            & $10^2$    \\ 
+\hline 
+$6$         & $10$            & $10^2$ & $6\cdot 10^2$   & $10^4$    \\ 
+\hline 
+$9$         & $31$            & $10^3$ & $9\cdot 10^3$   & $10^6$    \\ 
+\hline 
+$13$        & $10^2$          & $10^4$ & $1.3\cdot 10^5$ & $10^8$    \\ 
+\hline 
+$16$        & $3.1\cdot 10^2$ & $10^5$ & $1.6\cdot 10^6$ & $10^{10}$ \\ 
+\hline 
+$19$        & $10^3$          & $10^6$ & $1.9\cdot 10^7$ & $10^{12}$ \\ 
+\hline 
+\end{tabular} 
+\end{center} 
+\end{table} 
+
+
+# Quelques exercices (1/3)
+
+## Complexité de l'algorithme de test de primalité naïf?
+
+```C
+for (i = 2; i < sqrt(N); ++i) {
+    if (N % i == 0) {
+        return false;
+    }
+}
+return true;
+```
+
+. . .
+
+## Réponse 
+
+$$
+\mathcal{O}(\sqrt{N}).
+$$
+
+# Quelques exercices (2/3)
+
+## Complexité de trouver le minimum d'un tableau?
+
+```C
+int min = MAX;
+for (i = 0; i < N; ++i) {
+    if (tab[i] < min) {
+        min = tab[i];
+    }
+}
+return min;
+```
+
+. . .
+
+## Réponse 
+
+$$
+\mathcal{O}(N).
+$$
+
+# Quelques exercices (3/3)
+
+## Complexité du tri par sélection?
+
+```C
+int ind = 0
+while (ind < SIZE-1) {
+    min = find_min(tab[ind:SIZE]);
+    swap(min, tab[ind]);
+    ind += 1
+}
+```
+
+. . .
+
+## Réponse
+
+### `min = find_min`
+
+$$
+(N-1)+(N-2)+...+2+1=\sum_{i=1}^{N-1}i=N\cdot(N-1)/2=\mathcal{O}(N^2).
+$$
+
+## Finalement
+
+$$
+\mathcal{O}(N^2\mbox{ comparaisons}) + \mathcal{O}(N\mbox{swaps})=\mathcal{O}(N^2).
+$$
+
+# Tri par insertion (1/3)
+
+## But
+
+* trier un tableau par ordre croissant
+
+## Algorithme
+
+Prendre un élément du tableau et le mettre à sa place parmis les éléments déjà
+triés du tableau.
+
+![Tri par insertion d'un tableau d'entiers](figs/tri_insertion.svg)
+
+# Tri par insertion (2/3)
+
+## Exercice: Proposer un algorithme (en C)
+
+. . .
+
+```C
+void tri_insertion(int N, int tab[N]) {
+    for (int i = 1; i < N; i++) {
+        int tmp = tab[i];
+        int pos = i;
+        while (pos > 0 && tab[pos - 1] > tmp) {
+            tab[pos] = tab[pos - 1];
+            pos      = pos - 1;
+        }
+        tab[pos] = tmp;
+    }
+}
+```
+
+# Tri par insertion (3/3)
+
+## Question: Quelle est la complexité?
+
+. . .
+
+* Parcours de tous les éléments ($N-1$ passages dans la boucle)
+    * Placer: en moyenne $i$ comparaisons et affectations à l'étape $i$
+* Moyenne: $\mathcal{O}(N^2)$
+
+. . .
+
+* Pire des cas, liste triée à l'envers: $\mathcal{O}(N^2)$
+* Meilleurs des cas, liste déjà triée: $\mathcal{O}(N)$
+
+# L'algorithme à la main
+
+## Exercice *sur papier*
+
+* Trier par insertion le tableau `[5, -2, 1, 3, 10]`
+
+```C
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+# Problème des 8-reines
+
+* Placer 8 reines sur un échiquier de $8 \times 8$.
+* Sans que les reines ne puissent se menacer mutuellement (92 solutions). 
+
+## Conséquence
+
+* Deux reines ne partagent pas la même rangée, colonne, ou diagonale.
+* Donc chaque solution a **une** reine **par colonne** ou **ligne**.
+
+## Généralisation
+
+* Placer $N$ reines sur un échiquier de $N \times
+  N$. 
+- Exemple de **backtracking** (retour en arrière) $\Rightarrow$ récursivité.
+
+![Problème des 8-reines. Source:
+[wikipedia](https://fr.wikipedia.org/wiki/Problème_des_huit_dames)](./figs/fig_recursivite_8_reines.png){width=35%}
+
+# Problème des 2-reines
+
+![Le problème des 2 reines n'a pas de solution.](figs/2reines.svg){width=50%}
+
+# Comment trouver les solutions?
+
+* On pose la première reine sur la première case disponible.
+* On rend inaccessibles toutes les cases menacées.
+* On pose la reine suivante sur la prochaine case non-menacée.
+* Jusqu'à ce qu'on puisse plus poser de reine.
+* On revient alors en arrière jusqu'au dernier coup où il y avait plus qu'une
+  possibilité de poser une reine.
+* On recommence depuis là.
+
+. . .
+
+* Le jeu prend fin quand on a énuméré *toutes* les possibilités de poser les
+  reines.
+
+# Problème des 3-reines
+
+![Le problème des 3 reines n'a pas de solution non plus.](figs/3reines.svg)
+
+# Problème des 4-reines
+
+![Le problème des 4 reines a une solution.](figs/4reines.svg)
+
+# Problème des 4-reines, symétrie
+
+![Le problème des 4 reines a une autre solution (symétrie
+horizontale).](figs/4reines_sym.svg)
+
+# Problème des 5 reines
+
+## Exercice: Trouver une solution au problème des 5 reines
+
+* Faire une capture d'écran / une photo de votre solution et la poster sur
+  matrix.
+
+```C
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+# Quelques observations sur le problème
+
+* Une reine par colonne au plus.
+* On place les reines sur des colonnes successives.
+* On a pas besoin de "regarder en arrière" (on place "devant" uniquement).
+* Trois étapes:
+    * On place une reine dans une case libre.
+    * On met à jour le tableau.
+    * Quand on a plus de cases libres on "revient dans le temps" ou c'est qu'on
+      a réussi.
+
+# Le code du problème des 8 reines (1/N)
+
+## Quelle structure de données?
+
+. . .
+
+Une matrice de booléens fera l'affaire:
+
+```C
+bool board[n][n];
+```
+
+## Quelles fonctionnalités?
+
+. . .
+
+```C
+// Pour chaque ligne placer la reine sur toutes les colonnes
+//    et compter les solutions
+void nbr_solutions(board, column, counter);
+// Copier un tableau dans un autre
+void copy(board_in, board_out);
+// Placer la reine à li, co et rendre inaccessible devant
+void placer_devant(board, li, co);
+```
+
+# Le code du problème des 8 reines (2/N)
+
+## Le calcul du nombre de solutions
+
+```C
+// Calcule le nombre de solutions au problème des <n> reines
+nbr_solutions(board, column, count)
+   // pour chaque ligne 
+       // si la case libre
+          // si column < n - 1
+              // copier board dans un "new" board, 
+              //   y poser une reine
+              //   et mettre à jour ce "new" board
+              // nbr_solutions(new_board, column+1, count)
+          // sinon
+              // on a posé la n-ème et on a gagné
+              // count += 1
+```
+
+# Le code du problème des 8 reines (3/N)
+
+## Le calcul du nombre de solutions
+
+```C
+// Placer une reine et mettre à jour
+placer_devant(board, ligne, colonne)
+    // board est occupé à ligne/colonne
+        // toutes les cases des colonnes
+        //    suivantes sont mises à jour
+```
+
+# Le code du problème des 8 reines (4/N)
+
+## Compris? Alors écrivez le code et postez le!
+
+. . .
+
+## Le nombre de solutions
+
+\footnotesize
+
+```C
+// Calcule le nombre de solutions au problème des <n> reines
+void nb_sol(int n, bool board[n][n], int co, int *ptr_cpt) {
+    for (int li = 0; li < n; li++) {
+        if (board[li][co]) {
+            if (co < n-1) {
+                bool new_board[n][n]; // alloué à chaque nouvelle tentative
+                copy(n, board, new_board);         
+                prises_devant(n, new_board, li, co);
+                nb_sol(n, new_board, co+1, ptr_cpt);
+            } else {
+                *ptr_cpt = (*ptr_cpt)+1;
+            }
+        }
+    }
+}
+```
+
+
+# Le code du problème des 8 reines (5/N)
+
+\footnotesize
+
+## Placer devant
+
+```C
+// Retourne une copie du tableau <board> complété avec les positions
+// prises sur la droite droite par une reine placée en <board(li,co)>
+void prises_devant(int n, bool board[n][n], int li, int co) {
+    board[li][co] = false; // position de la reine
+    for (int j = 1; j < n-co; j++) {
+        // horizontale et diagonales à droite de la reine
+        if (j <= li) {
+            board[li-j][co+j] = false;
+        }
+        board[li][co+j] = false;
+        if (li+j < n) {
+            board[li+j][co+j] = false;
+        }
+    }
+}
+```
-- 
GitLab