Algorithmes de type "Diviser pour régner"

I. Définition, principes, cas d'utilisation

A. Définition

Un algorithme de type "diviser pour régner" est un algorithme qui, pour résoudre un problème de taille n, utilise la résolution d'un ou plusieurs problèmes de tailles inférieures à n. Il s'agit donc souvent d'algorithmes récursifs.

B. Caractéristiques générales

Ces algorithmes présentent en général les caractéristiques suivantes :

II. Quelques exemples classiques

A. Exemples simples

Pour déterminer le maximum de 4 nombres, on peut passer par le maximum de 2 nombres, selon différentes façons d'ailleurs :

Pour déterminer le maximum d'une liste de taille n, on peut passer par le maximum d'une liste de taille n-1 :

        max([a1, a2, ... an]) = max (a1, max([a2, ... an]))
      

B. Exemples plus complexes

Le problème des tours de Hanoi est un problème typique des problèmes avec une résolution récursive :

deplacer(n, A, B, C):
  deplacer(n-1, A, C, B)
  deplacer(1, A, B, C)
  deplacer(n-1, C, B, A)
      

Exercice 1 : écrire un programme donnant la solution au problème des tours de Hanoi à n disques.

        from sys import argv

        def hanoi(n, depart, arrivee, intermediaire):
            if n < 0 :
                raise "Nombre de disque négatif !"
            if n == 0 :
                return
            elif n == 1:
                print("déplacer 1 disque de", depart, "à", arrivee)
            else:
                hanoi(n-1,depart, intermediaire, arrivee)
                hanoi(1, depart, arrivee, intermediaire)
                hanoi(n-1, intermediaire, arrivee, depart)

        hanoi(int(argv[1]), "A", "B", "C")
      

D'autres algorithmes classiques reposent sur le principe "Diviser pour Régner" :

Exercice 2 : écrire un programme de recherche dichotomique dans une liste triée

        from sys import argv
        def recherche(liste, valeur, debutZoneRecherche, finZoneRecherche):
          """
          Fonction renvoyant l'indice d'une valeur si elle est présente dans liste,
          et renvoyant -1 sinon
          """
          if len(liste) == 0:
            return -1
          indiceMilieu = int((debutZoneRecherche+finZoneRecherche)/2)
          valeurMediane = liste[indiceMilieu]
          if valeurMediane == valeur:
            return indiceMilieu
          elif valeur < valeurMediane and indiceMilieu > debutZoneRecherche:
            return recherche(liste, valeur, debutZoneRecherche, indiceMilieu-1)
          elif valeur > valeurMediane and indiceMilieu < finZoneRecherche:
            return recherche(liste, valeur, indiceMilieu+1, finZoneRecherche)
          else:
            return -1

        listeTest = [1, 2, 4, 6, 7, 9, 10, 12, 16, 20]
        print(listeTest)
        print(recherche(listeTest, int(argv[1]), 0, len(listeTest)-1))
      

Exercice 3 : écrire un programme implantant un algorithme de tri rapide sur une liste

        from random import randint

        liste = []
        for i in range(0, 30):
            liste.append(randint(1,100))

        print(liste)

        def triRapide(liste):
            """
            fonction qui initialise la fonction récursive de tri rapide d'une liste.
            """
            trier(liste, 0, len(liste+1))

        def trier(liste, indiceDebut, indiceFin):
            """
            fonction récursive qui trie une liste en utilisant la méthode trie rapide.
            """
            if (indiceFin <= indiceDebut):
                return
            indicePivot = randint(indiceDebut, indiceFin)
            pivot = liste[indicePivot]
            indicePivot = partitionner(liste, pivot, indiceDebut, indicePivot, indiceFin)
            trier(liste, indiceDebut, indicePivot-1)
            trier(liste, indicePivot+1, indiceFin)

        def partitionner(liste, pivot, indiceDebut, indicePivot, indiceFin):
            """
            fonction qui partitionne une liste en fonction d'un pivot en mettant à gauche
            du pivot les éléments plus petits que le pivot et à droite les éléments plus
            grand. L'indice du pivot est susceptible d'être modifié au cours du traitement ;
            il est donc renvoyé par cette fonction.
            """
            termine = False
            indiceCourant = indiceDebut
            while indiceCourant <= indiceFin:
                if liste[indiceCourant] > pivot and indiceCourant < indicePivot:
                    liste[indicePivot] = liste[indiceCourant]
                    liste[indiceCourant] = liste[indicePivot-1]
                    liste[indicePivot-1] = pivot
                    indicePivot = indicePivot - 1
                elif liste[indiceCourant] < pivot and indiceCourant > indicePivot:
                    liste[indicePivot] = liste[indiceCourant]
                    liste[indiceCourant] = liste[indicePivot+1]
                    liste[indicePivot+1] = pivot
                    indicePivot = indicePivot + 1
                else:
                    indiceCourant = indiceCourant + 1
            return indicePivot

        triRapide(liste)
        print(liste)
      

Exercice 4 : écrire un programme implantant un algorithme de tri fusion sur une liste

        from random import randint

        liste = []
        for i in range(0, 30):
            liste.append(randint(1,100))

        print(liste)

        def trier(liste):
            """
            renvoie une version triée d'une liste en utilisant la méthode du tri fusion.
            """
            taille = len(liste)
            if taille <= 1:
                return liste
            milieu = int(taille/2)
            return fusionner(trier(liste[:milieu]), trier(liste[milieu:]))

        def fusionner(listeA, listeB):
            """
            fonction qui fusionne 2 listes triées
            """
            fusion = []
            teteA = listeA[0]
            teteB = listeB[0]
            while (len(listeA) > 0 and len(listeB) > 0):
                if teteA < teteB:
                    fusion.append(teteA)
                    listeA.pop(0)
                    if len(listeA) > 0:
                        teteA = listeA[0]
                else:
                    fusion.append(teteB)
                    listeB.pop(0)
                    if len(listeB) > 0:
                        teteB = listeB[0]
            fusion = fusion + listeA + listeB
            return fusion

        resultat = trier(liste)
        print(resultat)