Fiche récapitulative générée pour impression / export PDF.
Licence 1 · Informatique L1 — Introduction à Python pour les mathématiques
Algorithmes simples
Algorithmes simples
### 1. Recherche dans une liste (recherche séquentielle)
Pour savoir si une valeur v se trouve dans une liste L, on parcourt la liste élément par élément :
> def recherche(L, v):
> for x in L:
> if x == v:
> return True
> return False
Cette méthode, appelée recherche séquentielle, a un coût proportionnel à la longueur de la liste dans le pire cas (la valeur n'est pas présente, ou se trouve en dernière position) : on dit qu'elle est de complexité linéaire, où .
Variante : trouver l'indice d'une valeur.
> def indice(L, v):
> for i in range(len(L)):
> if L[i] == v:
> return i
> return -1
On renvoie souvent par convention pour signaler que la valeur n'a pas été trouvée.
### 2. Tri par sélection
Le tri par sélection construit la liste triée en répétant le principe suivant : trouver le plus petit élément restant et le placer en tête.
> def tri_selection(L):
> n = len(L)
> for i in range(n):
> indice_min = i
> for j in range(i+1, n):
> if L[j] < L[indice_min]:
> indice_min = j
> L[i], L[indice_min] = L[indice_min], L[i]
> return L
À chaque étape , on cherche le minimum parmi les éléments d'indices (la partie non encore triée), puis on l'échange avec l'élément d'indice .
Exemple résolu : trier .
- : minimum de est (indice ) → échange :
- : minimum de (indices à ) est , déjà en place :
- : minimum de est (indice ) → échange :
- : minimum de est , déjà en place : (trié)
### 3. Tri par insertion (alternative)
Le tri par insertion construit la partie triée en insérant chaque nouvel élément à sa bonne place parmi les éléments déjà triés :
> def tri_insertion(L):
> for i in range(1, len(L)):
> cle = L[i]
> j = i - 1
> while j >= 0 and L[j] > cle:
> L[j+1] = L[j]
> j = j - 1
> L[j+1] = cle
> return L
### 4. Calcul de moyenne et de somme
> def somme(L):
> s = 0
> for x in L:
> s = s + x
> return s
>
> def moyenne(L):
> return somme(L) / len(L)
### 5. Calcul itératif du PGCD (algorithme d'Euclide)
Le PGCD (plus grand commun diviseur) de deux entiers et se calcule par l'algorithme d'Euclide, fondé sur la propriété , avec :
> def pgcd(a, b):
> while b != 0:
> a, b = b, a % b
> return a
Exemple résolu : .
- : → nouveau couple
- : →
- : →
- : on renvoie .
Donc .
### 6. Résumé des complexités
| Algorithme | Complexité (pire cas) |
|---|---|
| Recherche séquentielle | |
| Tri par sélection | |
| Tri par insertion | |
| Algorithme d'Euclide | |
Exercices de la leçon
Exercice 1
Que renvoie recherche([3, 7, 1], 7) pour la fonction de recherche séquentielle du cours ?
Corrigé
La valeur est présente dans la liste (à l'indice ), donc la fonction recherche (qui renvoie un booléen, pas un indice) renvoie True.
Exercice 2
Quel est le pgcd de et ?
Corrigé
Par l'algorithme d'Euclide détaillé dans le cours : .
Exercice 3
Vrai ou faux : le tri par sélection trouve, à chaque étape, le plus petit élément restant et le place en tête de la partie non triée.
Corrigé
Vrai, c'est exactement le principe du tri par sélection : à l'étape , on sélectionne le minimum de la sous-liste et on l'échange avec .
Exercice 4
Quelle valeur renvoie la fonction indice(L, v) du cours si v n'est pas présent dans L ?
Corrigé
Par convention, la fonction renvoie lorsque la valeur recherchée n'a été trouvée à aucun indice de la liste, après avoir parcouru tous les éléments.
Exercice 5
Quelle est la complexité (en pire cas) de la recherche séquentielle dans une liste de longueur ?
Corrigé
Dans le pire cas (valeur absente, ou en dernière position), la recherche séquentielle examine les éléments de la liste : complexité linéaire .
Exercice 6
Après la première itération () du tri par sélection sur , quel est l'état de la liste ?
Corrigé
Le minimum de toute la liste est , à l'indice . On l'échange avec l'élément d'indice (qui est ) : .
Exercice 7
Vrai ou faux : a, b = b, a % b en Python échange et met à jour simultanément les deux variables, en utilisant l'ancienne valeur de a pour calculer le modulo.
Corrigé
Vrai. En Python, l'affectation multiple a, b = expr1, expr2 évalue d'abord toutes les expressions à droite avec les valeurs courantes, puis effectue les affectations. Donc a % b utilise bien l'ancienne valeur de a (et de b) avant toute modification.
Exercice 8
Quelle est la complexité (pire cas) du tri par sélection sur une liste de éléments ?
Corrigé
Le tri par sélection effectue, pour chacune des étapes, une recherche du minimum parmi en moyenne éléments restants : le nombre total de comparaisons est de l'ordre de , soit .
Exercice 9
Calculer la moyenne de la liste à l'aide des fonctions somme et moyenne du cours.
Corrigé
. .
Exercice 10
Modifier la fonction recherche pour qu'elle compte le nombre de comparaisons effectuées avant de trouver la valeur (ou avant de conclure son absence). Donner le code modifié.
Corrigé
Une solution possible :
def recherche_comptee(L, v):
compteur = 0
for x in L:
compteur = compteur + 1
if x == v:
return True, compteur
return False, compteur
On incrémente un compteur à chaque comparaison effectuée (à chaque tour de boucle), et on le renvoie en plus du résultat booléen. Python permet de renvoyer plusieurs valeurs sous forme de tuple avec return a, b.
Exercice 11
Dérouler le tri par insertion sur la liste étape par étape () et donner le résultat final.
Corrigé
: clé . On compare à , donc on décale vers la droite et on insère en tête : .
: clé . On compare à : , pas de décalage : inchangée.
: clé . On compare à : décalage, puis à : décalage, puis à : on insère juste après : .
Le résultat final est la liste triée .
Exercice 12
Démontrer que l'algorithme d'Euclide se termine toujours en un nombre fini d'étapes, pour tous entiers donnés au départ.
Corrigé
À chaque itération de la boucle while b != 0, le couple devient . Or, par définition du reste de la division euclidienne, (strictement).
Donc la nouvelle valeur de (qui est ) est strictement inférieure à l'ancienne valeur de . La suite des valeurs successives de est donc une suite strictement décroissante d'entiers naturels.
Une telle suite ne peut pas décroître indéfiniment (elle est minorée par ) : elle atteint nécessairement la valeur après un nombre fini d'étapes, ce qui termine la boucle while.
Exercice 13
Pourquoi le tri par sélection effectue-t-il toujours environ comparaisons, indépendamment de l'ordre initial de la liste (contrairement au tri par insertion) ?
Corrigé
La boucle interne du tri par sélection (recherche du minimum dans la partie restante) s'exécute toujours sur tous les éléments restants, sans condition d'arrêt anticipée, quel que soit leur ordre. C'est pourquoi sa complexité est toujours , alors que le tri par insertion peut s'arrêter plus tôt (boucle while) si la liste est déjà presque triée.
Exercice 14
Écrire une fonction est_trie(L) qui renvoie True si la liste L est triée par ordre croissant, False sinon.
Corrigé
Une solution possible :
def est_trie(L):
for i in range(len(L) - 1):
if L[i] > L[i+1]:
return False
return True
On parcourt les paires d'éléments consécutifs ; dès qu'on en trouve une dans le mauvais ordre (), on renvoie False immédiatement. Si aucune paire n'est dans le mauvais ordre après le parcours complet, la liste est triée : on renvoie True. On utilise range(len(L)-1) pour éviter une erreur d'indice hors limites en comparant le dernier élément à un suivant inexistant.
Exercice 15
On veut calculer le PGCD de trois entiers . Proposer une fonction pgcd3(a, b, c) réutilisant la fonction pgcd du cours, en justifiant l'identité mathématique utilisée.
Corrigé
Une solution possible :
def pgcd3(a, b, c):
return pgcd(pgcd(a, b), c)
Justification : un entier divise simultanément si et seulement si divise et divise (car et ). Donc l'ensemble des diviseurs communs à est exactement l'ensemble des diviseurs communs à et , ce qui donne . Cette associativité permet de réduire le calcul du pgcd de nombres à des appels successifs de la fonction à deux arguments.
AlphaMath Académie · Algorithmes simples · Informatique L1 — Introduction à Python pour les mathématiques