I1 — Algorithmes et complexité
Objectif du chapitre. Apprendre à concevoir des algorithmes (recherche séquentielle et dichotomique, tris par insertion et fusion), à introduire la récursivité (le tri fusion en dépend) et à évaluer la complexité d'un algorithme en grand . Ce chapitre porte les deux capacités exigibles de l'IPT : I1.dichotomie et I1.complexite-algorithme.
Ce chapitre suppose les bases de Python du chapitre I1 — Bases Python et représentation des nombres (variables, boucles, fonctions, listes).
Notions
1. La récursivité (introduction)
Avant d'aborder le tri fusion, il faut comprendre la récursivité : une fonction récursive est une fonction qui s'appelle elle-même pour résoudre un sous-problème plus petit. Deux ingrédients sont indispensables :
- un cas de base (la condition d'arrêt, sans laquelle la récursion ne s'arrête jamais) ;
- un pas récursif qui réduit le problème à un cas plus petit (qui doit tendre vers le cas de base).
Exemple : factorielle. , avec .
def factorielle(n):
if n == 0: # cas de base
return 1
return n * factorielle(n - 1) # pas récursif : problème plus petit
factorielle(4) déroule en 4 * factorielle(3) = 4 * 3 * factorielle(2) = 4 * 3 * 2 * factorielle(1) = 4 * 3 * 2 * 1 * factorielle(0) = 24. Chaque appel réduit de 1 jusqu'au cas de base .
Exemple : somme d'une liste (récursif).
def somme(lst):
if len(lst) == 0: # cas de base
return 0
return lst[0] + somme(lst[1:]) # premier élément + somme du reste
Sans cas de base (ou si le pas récursif ne réduit pas le problème), la récursion ne s'arrête jamais : on épuise la pile d'appels (erreur RecursionError en Python). Il faut toujours vérifier que le pas récursif converge vers le cas de base.
2. Recherche séquentielle et dichotomique
Recherche séquentielle. La recherche séquentielle (linéaire) parcourt la liste élément par élément ; la complexité est (au pire : comparaisons) ; elle fonctionne sur une liste non triée.
Recherche dichotomique. La recherche dichotomique (binaire) divise l'intervalle de recherche en deux à chaque itération ; elle exige une liste triée ; la complexité est (au pire : comparaisons) ; à chaque étape, on compare l'élément central à la valeur cherchée et on élimine la moitié de l'intervalle.
Exemple (dichotomie).
def recherche_dichotomique(lst, x):
a, b = 0, len(lst) - 1
while a <= b:
m = (a + b) // 2
if lst[m] == x:
return m
elif lst[m] < x:
a = m + 1
else:
b = m - 1
return -1
La complexité est : pour , au plus