Adloun

Diviser pour régner

Cours · NSI (terminale), chapitre 6 · terminale, spécialité numérique et sciences informatiques · le début du chapitre, la suite sur Adloun

Diviser pour régner : un problème est coupé en deux, chaque moitié est résolue, puis les solutions sont fusionnées.

La stratégie diviser pour régner (en anglais divide and conquer) est l'un des grands paradigmes de conception d'algorithmes. Plutôt que d'attaquer un problème de front, on le découpe en sous-problèmes plus petits, de même nature, que l'on résout indépendamment avant de recombiner leurs solutions. Cette idée, déjà présente dans la recherche dichotomique vue en classe de Première, conduit à des algorithmes particulièrement efficaces comme le tri fusion ou le tri rapide.

Dans ce chapitre, nous présentons le principe général, puis nous l'illustrons sur trois algorithmes classiques. Nous analysons leur complexité et nous les comparons aux approches naïves afin de mesurer le gain obtenu.

6.1 Le principe « diviser pour régner »

Définition 6.1Diviser pour régner

Un algorithme suit le paradigme diviser pour régner lorsqu'il résout un problème en trois étapes :

  • Diviser : découper le problème en un ou plusieurs sous-problèmes de taille plus petite, de même nature ;
  • Régner : résoudre chaque sous-problème, le plus souvent de manière récursive ; lorsque la taille devient suffisamment petite, on résout directement (cas de base) ;
  • Combiner : assembler les solutions des sous-problèmes pour construire la solution du problème initial.

Méthode : Concevoir un algorithme « diviser pour régner »

Pour appliquer ce paradigme, on se pose systématiquement quatre questions :

  • Quel est le cas de base (le plus petit cas, résolu sans récursion) ?
  • Comment découper les données en sous-problèmes plus petits ?
  • Comment combiner (fusionner) les sous-solutions ?
  • La taille décroît-elle strictement à chaque appel, garantissant la terminaison ?

Le caractère récursif de ces algorithmes est essentiel : un problème de taille est ramené à des problèmes de taille (ou ), eux-mêmes ramenés à des problèmes encore plus petits, jusqu'à atteindre le cas de base.

Exemple 6.2Calcul d'une puissance par exponentiation rapide

Pour calculer , l'approche naïve effectue multiplications. En remarquant que si est pair, on divise l'exposant par deux à chaque étape.


def puissance(x, n):
    if n == 0:              # cas de base
        return 1
    demi = puissance(x, n // 2)   # diviser + regner
    if n % 2 == 0:
        return demi * demi        # combiner
    else:
        return demi * demi * x

Le nombre de multiplications passe ainsi de à .

6.2 La recherche dichotomique

La recherche dichotomique permet de trouver un élément dans un tableau trié bien plus vite qu'une recherche séquentielle.

Définition 6.3Recherche dichotomique

Soit tab un tableau trié par ordre croissant et cible une valeur recherchée. La recherche dichotomique consiste à comparer cible à l'élément du milieu :

  • s'ils sont égaux, l'élément est trouvé ;
  • si cible est plus petite, on poursuit dans la moitié gauche ;
  • sinon, on poursuit dans la moitié droite.

À chaque étape, la zone de recherche est divisée par deux : c'est bien une application du paradigme « diviser pour régner ».

Exemple 6.4Recherche dichotomique itérative

def recherche_dichotomique(tab, cible):
    g, d = 0, len(tab) - 1
    while g <= d:
        m = (g + d) // 2
        if tab[m] == cible:
            return m
        elif tab[m] < cible:
            g = m + 1
        else:
            d = m - 1
    return -1   # cible absente

La fonction renvoie l'indice de cible, ou si elle est absente.

Exercices du chapitre

La suite du cours · Tous les exercices du chapitre