27 - Algorithmique
Les exercices se font dans Thonny, dans le fichier 27_algorithmique.py.
Cours associé : 19 - Dichotomie .
Exercice 1 : QCM – vérification des prérequis
Pour chaque question, une seule réponse est correcte.
1. Quelle est la complexité d’un parcours séquentiel d’une liste de $n$ éléments ?
- A. $O(1)$
- B. $O(\log n)$
- C. $O(n)$
- D. $O(n^2)$
Correction publiée après la séance.
2. Que signifie « prouver la terminaison » d’un algorithme ?
- A. Vérifier qu’il donne le bon résultat
- B. Montrer qu’il finit toujours en un nombre fini d’étapes
- C. Calculer sa complexité
- D. Écrire ses tests
Correction publiée après la séance.
3. Pour prouver la terminaison d’une boucle while, on utilise :
- A. Un invariant de boucle
- B. Un variant de boucle
- C. Une assertion
- D. Un test unitaire
Correction publiée après la séance.
4. La recherche dichotomique nécessite que le tableau soit :
- A. De taille paire
- B. Constitué d’entiers
- C. Trié
- D. Sans doublons
Correction publiée après la séance.
Exercice 2 : recherche séquentielle pas à pas
On considère la fonction suivante :
def chercher(L, x):
for i in range(len(L)):
if L[i] == x:
return True
return False
- Recopier et compléter la trace de
chercher([3, 8, 1, 7, 5], 7). La première ligne est donnée.
| Tour | i | L[i] | L[i] == 7 ? | Action |
|---|---|---|---|---|
| 1 | 0 | 3 | Non | on continue |
| 2 | ||||
| 3 | ||||
| 4 |
Indice
À chaque tour, i augmente de 1 et L[i] est l’élément d’indice i de [3, 8, 1, 7, 5]. Dès que L[i] == 7 est vrai, la fonction exécute return True : la boucle s’arrête, et la trace aussi.
Combien de tours la boucle fait-elle pour
chercher([3, 8, 1, 7, 5], 4)? Que renvoie la fonction ?Indice
4 est-il dans la liste ? Si la condition
L[i] == xn’est jamais vraie, la boucle va jusqu’au bout derange(len(L)), puis la fonction exécute la ligne qui suit la boucle.Pourquoi la boucle se termine-t-elle toujours ? Donner un variant.
Indice
Un variant est un entier positif qui diminue à chaque tour. Ici,
iaugmente de 1 à chaque tour sans pouvoir dépasserlen(L): quelle quantité, calculée aveclen(L)eti, diminue alors à chaque tour ?Pour une liste de $n$ éléments, combien de comparaisons faut-il au pire ? Dans quel cas ?
Indice
Le pire cas est celui où la boucle fait le plus de tours : que doit-il se passer pour que tous les éléments soient comparés à
x?
Correction publiée après la séance.
Exercice 3 : parcours séquentiel guidé
3.1 Recherche d’un élément
Compléter la fonction suivante, puis répondre aux questions :
def est_element(a, L):
"""Renvoie True si a est dans L, False sinon."""
for ___ in ___:
if ___ == ___:
return ___
return ___
Indice
La boucle parcourt les éléments de L avec une variable dont on choisit le nom, et compare chacun à a. Le return placé dans la boucle sert quand on a trouvé a, celui placé après la boucle quand on ne l’a pas trouvé.
La boucle se termine-t-elle toujours ? Quel est le variant ?
Indice
Combien de tours fait au plus une boucle
forqui parcourt une liste ? Le variant mesure ce qui reste à faire : quelle quantité diminue de 1 à chaque tour ?L’algorithme est-il correct ? Justifier.
Indice
Examiner les deux cas :
aest dansL, etan’est pas dansL. Dans chacun, que renvoie la fonction, et est-ce le résultat attendu ?Quelle est la complexité au pire cas ?
Indice
Compter les comparaisons
== aquandaest absent deL: combien y en a-t-il pour une liste de $n$ éléments ?
Correction publiée après la séance.
3.2 Calcul de moyenne (météo)
Écrire une fonction moyenne(L) qui calcule la moyenne d’une liste de flottants (par exemple des températures). Déterminer sa complexité.
Indice
Additionner les éléments dans un accumulateur, puis diviser par len(L). Pour la complexité, compter combien de tours fait la boucle pour une liste de $n$ éléments.
Code à copier puis compléter
def moyenne(L):
total = 0
for x in L:
total = ...
return ...
Correction publiée après la séance.
Exercice 4 : recherche d’un extremum (sport)
Le tableau suivant donne les temps (en secondes) de cinq coureurs sur un 100 m :
[11.2, 10.8, 12.1, 10.5, 11.7]
Écrire une fonction
indice_min(L)qui renvoie l’indice du minimum d’une liste (sans utilisermin()niindex()).Indice
Garder l’indice
i_mindu plus petit élément vu jusqu’ici, en partant de 0. Parcourir les indices suivants et mettrei_minà jour quandL[i]est plus petit queL[i_min].Code à copier puis compléter
def indice_min(L): i_min = 0 for i in range(1, len(L)): if ...: i_min = ... return i_minEn déduire le numéro du coureur le plus rapide.
Indice
Le plus rapide a le plus petit temps. Les indices commencent à 0, alors que les coureurs sont numérotés à partir de 1.
Prouver la terminaison et la correction. Déterminer la complexité.
Indice
Terminaison : quelle quantité entière diminue à chaque tour de la boucle ? Correction : que contient
i_minaprès le tour qui a examiné l’élément d’indicei? Cette propriété, vraie à chaque tour, est un invariant.
Correction publiée après la séance.
Exercice 5 : invariant et correction – factorielle
On considère le programme suivant :
def factorielle(n):
i = 0
f = 1
while i < n:
i = i + 1
f = f * i
return f
Justifier que la boucle n’est pas infinie (donner le variant).
Indice
Comment évolue
ià chaque tour, et quand la conditioni < ndevient-elle fausse ? Le variant est une quantité entière, calculée avecneti, qui diminue de 1 à chaque tour.Calculer
factorielle(4)et vérifier que le résultat est $4! = 24$.Indice
Dresser un tableau avec une ligne par tour, qui donne les valeurs de
iet defà la fin du tour :ipasse de 0 à 4.Montrer que $f = i!$ est un invariant de la boucle.
Indice
Deux étapes : vérifier que $f = i!$ est vrai avant le premier tour (que valent
ietf?), puis montrer que si $f = i!$ au début d’un tour, c’est encore vrai à la fin, aprèsi = i + 1etf = f * i.En déduire que l’algorithme est correct (c’est-à-dire que
factorielle(n)renvoie $n!$).Indice
Que vaut
ià la sortie de la boucle, quandi < nest devenu faux ? L’invariant donne alors la valeur def.
Correction publiée après la séance.
Exercice 6 : recherche dichotomique
Écrire une fonction
dichotomie(L, x)qui cherche la valeurxdans une liste triéeLet renvoieTruesi elle est présente,Falsesinon.Indice
Deux indices,
getd, délimitent la zone oùxpeut encore se trouver : au départ, toute la liste. Tant que cette zone n’est pas vide, comparerxà l’élément du milieu : s’il est égal,xest présent ; s’il est plus petit quex, poursuivre la recherche à droite du milieu, sinon à gauche.Code à copier puis compléter
def dichotomie(L, x): g = 0 d = len(L) - 1 while g <= d: m = (g + d) // 2 if L[m] == x: return ... elif L[m] < x: g = ... else: d = ... return FalseTracer l’exécution sur
L = [2, 5, 8, 12, 16, 23, 38, 42]avecx = 23.Indice
Faire un tableau avec une ligne par tour et les colonnes
g,d,m,L[m], la comparaison et l’action. Au premier tour,g = 0,d = 7etm = (0 + 7) // 2.Prouver la terminaison (variant : $d - g$). Quelle est la complexité ?
Indice
À chaque tour, soit
gaugmente, soitddiminue, et la zone de recherche est coupée en deux. Combien de fois peut-on diviser $n$ par 2 avant d’arriver à moins de 1 ?
Correction publiée après la séance.
Exercice 7 : synthèse – annuaire téléphonique
Un annuaire est une liste de tuples (nom, numéro) triée par ordre alphabétique :
annuaire = [
("Dupont", "01 23 45 67 89"),
("Garcia", "06 12 34 56 78"),
("Lambert", "04 56 78 90 12"),
("Martin", "07 89 01 23 45"),
("Petit", "03 21 09 87 65"),
]
Écrire une fonction
recherche_seq(annuaire, nom)qui cherche un nom par parcours séquentiel et renvoie le numéro (ouNone).Indice
Parcourir l’annuaire en déballant chaque tuple :
for n, numero in annuaire:. Renvoyer le numéro dès quenest le nom cherché ; après la boucle, renvoyerNone.Code à copier puis compléter
def recherche_seq(annuaire, nom): for n, numero in annuaire: if ...: return ... return NoneÉcrire une fonction
recherche_dicho(annuaire, nom)qui fait la même chose par dichotomie (le tableau est trié alphabétiquement).Indice
Même algorithme que
dichotomieà l’exercice 6, en comparantannuaire[m][0], le nom de la case du milieu, au nom cherché : les chaînes se comparent avec<dans l’ordre alphabétique. Quand le nom est trouvé, renvoyerannuaire[m][1].Code à copier puis compléter
def recherche_dicho(annuaire, nom): g = 0 d = len(annuaire) - 1 while g <= d: m = (g + d) // 2 if annuaire[m][0] == nom: return ... elif annuaire[m][0] < nom: g = ... else: d = ... return NoneComparer le nombre de comparaisons effectuées pour trouver
"Petit"avec chaque méthode.Indice
Séquentiel : à quelle position se trouve
"Petit"dans l’annuaire ? Dichotomie : suivre l’algorithme sur les cinq noms, comme dans la trace de l’exercice 6.Si l’annuaire contenait un million d’entrées, combien de comparaisons faudrait-il au maximum avec chaque méthode ?
Indice
Séquentiel : dans le pire cas, on examine toutes les entrées. Dichotomie : combien de fois faut-il diviser un million par 2 pour arriver à 1 ? Comparer avec $2^{20}$, qui vaut environ un million.
Correction publiée après la séance.