-
orestis.malaspin authoredorestis.malaspin authored
- La récursivité (1/2)
- Exercice: réusinage et récursivité (2/4)
- Réusiner le code du PGCD avec une fonction récursive
- Étudier l'exécution
- Exercice: réusinage et récursivité (3/4)
- Réusiner le code du PGCD avec une fonction récursive
- Étudier l'exécution
- Effectuer l'empilage - dépilage
- Exercice: réusinage et récursivité (4/4)
- Écrire le code
- La suite de Fibonacci (1/2)
- Règle
- Exercice: écrire la fonction \mathrm{Fib} en récursif et impératif
- En récursif (6 lignes)
- La suite de Fibonacci (2/2)
- Et en impératif (11 lignes)
- Exponentiation rapide ou indienne (1/4)
- But: Calculer x^n
- Exponentiation rapide ou indienne (2/4)
- Exponentiation rapide ou indienne (3/4)
- Exponentiation rapide ou indienne de x^n
- Combien de calculs en terme de n?
- Exponentiation rapide ou indienne (4/4)
- Le vrai algorithme
- Exercice: écrire l'algorithme récursif correspondant
- Efficacité d'un algorithmique
- Mesure du temps CPU
- Programme simple: mesure du temps CPU
- Preuve sur un petit exemple
- Conclusion
- Analyse de complexité algorithmique (1/4)
- Exemple: recherche d'un élément dans une liste triée de taille N
- Analyse de complexité algorithmique (2/4)
- Recherche linéaire
- Analyse de complexité algorithmique (3/4)
- Recherche dichotomique
- Analyse de complexité algorithmique (4/4)
- Recherche dichotomique
- Linéaire vs dichotomique
- Notation pour la complexité
- Constante de proportionnalité
- Le \mathcal{O} de Leibnitz
- Ordres de grandeur
- Quelques exercices (1/3)
- Complexité de l'algorithme de test de primalité naïf?
- Réponse
- Quelques exercices (2/3)
- Complexité de trouver le minimum d'un tableau?
- Réponse
- Quelques exercices (3/3)
- Complexité du tri par sélection?
- Réponse
- min = find_min
- Finalement
title: "Récursivité et complexité"
date: "2021-11-03"
patat:
eval:
tai:
command: fish
fragment: false
replace: true
ccc:
command: fish
fragment: false
replace: true
images:
backend: auto
La récursivité (1/2)
-
Code récursif
int factorial(int n) { if (n > 1) { // Condition de récursivité return n * factorial(n - 1); } else { // Condition d'arrêt return 1; } }
. . .
* Code impératif
```C
int factorial(int n) {
int f = 1;
for (int i = 1; i < n; ++i) {
f *= i;
}
return f;
}
```
# Exercice: réusinage et récursivité (1/4)
## Réusiner le code du PGCD avec une fonction récursive
## Étudier l'exécution
```C
42 = 27 * 1 + 15
27 = 15 * 1 + 12
15 = 12 * 1 + 3
12 = 3 * 4 + 0
Exercice: réusinage et récursivité (2/4)
Réusiner le code du PGCD avec une fonction récursive
Étudier l'exécution
42 = 27 * 1 + 15 | PGCD(42, 27)
27 = 15 * 1 + 12 | PGCD(27, 15)
15 = 12 * 1 + 3 | PGCD(15, 12)
12 = 3 * 4 + 0 | PGCD(12, 3)
Exercice: réusinage et récursivité (3/4)
Réusiner le code du PGCD avec une fonction récursive
Étudier l'exécution
42 = 27 * 1 + 15 | PGCD(42, 27)
27 = 15 * 1 + 12 | PGCD(27, 15)
15 = 12 * 1 + 3 | PGCD(15, 12)
12 = 3 * 4 + 0 | PGCD(12, 3)
Effectuer l'empilage - dépilage
. . .
PGCD(12, 3) | 3
PGCD(15, 12) | 3
PGCD(27, 15) | 3
PGCD(42, 27) | 3
Exercice: réusinage et récursivité (4/4)
Écrire le code
. . .
int pgcd(int n, int m) {
if (n % m > 0) {
return pgcd(m, n % m);
} else {
return m;
}
}
La suite de Fibonacci (1/2)
Règle
\mathrm{Fib} en récursif et impératif
Exercice: écrire la fonction . . .
En récursif (6 lignes)
int fib(int n) {
if (n > 1) {
return fib(n - 1) + fib(n - 2);
}
return n;
}
La suite de Fibonacci (2/2)
Et en impératif (11 lignes)
int fib_imp(int n) {
int fib0 = 1;
int fib1 = 1;
int fib = n == 0 ? 0 : fib1;
for (int i = 2; i < n; ++i) {
fib = fib0 + fib1;
fib0 = fib1;
fib1 = fib;
}
return fib;
}
Exponentiation rapide ou indienne (1/4)
x^n
But: Calculer -
Algorithme naîf et impératif
int pow(x, n) { if (0 == n) { return 1; } for (int i = 1; i < n; ++i) { x *= x; } return x; }
. . .
- Complexité? Combien de multiplication en fonction de
n
?
Exponentiation rapide ou indienne (2/4)
-
Algorithme naïf et récursif
int pow(x, n) { if (n != 0) { return x * pow(x, n-1); } else { return 1; } }
Exponentiation rapide ou indienne (3/4)
x^n
Exponentiation rapide ou indienne de - Écrivons n=\sum_{i=0}^{d-1}b_i 2^i,\ b_i=\{0,1\}(écriture binaire surdbits, avecd\sim\log_2(n)).
- On a besoin de dcalculs pour lesx^{2^i}.
- On a besoin de dcalculs pour évaluer les produits de tous les termes.
n?
Combien de calculs en terme de . . .
-
nest représenté en binaire avecdbits\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
. . .
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
#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
petit exemple
Preuve sur unsource_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
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
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
Analyse de complexité algorithmique (3/4)
Recherche dichotomique
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
. . .
- Dans le meilleurs de cas il faut
1
comparaison. - Dans le pire des cas il faut \log_2(N)+1comparaisons
. . .
Linéaire vs dichotomique
-
Nvs\log_2(N)comparaisons logiques.
- Pour N=1000000:
1000000
vs21
comparaisons.
Notation pour la complexité
Constante de proportionnalité
- Pour la recherche linéaire ou dichotomique, on a des algorithmes qui sont
\sim Nou\sim \log_2(N)
- Qu'est-ce que cela veut dire?
. . .
- Temps de calcul est t=C\cdot N(oùCest le temps pris pour une comparaisons sur une machine/compilateur donné)
- La complexité ne dépend pas de C.
\mathcal{O} de Leibnitz
Le - 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
. . .
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
Quelques exercices (1/3)
Complexité de l'algorithme de test de primalité naïf?
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?
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?
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).