|
Diviser pour régner Une idée fondamentale |
|
| Introduction |
| Une idée fondamentale |
| Complexité et récurrences |
| Suites 2-rationnelles |
| Comportement asymptotique |
| Références |
La stratégie diviser pour régner consiste à briser un problème en sous-problèmes plus simples de même type, à résoudre ces sous-problèmes, puis à fusionner les résultats obtenus pour apporter une solution au problème posé. Il s'agit donc d'une démarche essentiellement récursive. Les algorithmes de ce type apparaissent comme composés de deux algorithmes; le premier partage le problème en sous-problèmes, le second algorithme fusionne les résultats partiels en le résultat global.
Tri. Le tri-fusion fournit un exemple clair de cette stratégie. La donnée est une liste d'items (on parle aussi de clés) pris dans un ensemble muni d'un ordre total; le but est d'obtenir une liste constituée de ces mêmes éléments mais rangés dans l'ordre [19, pp. 305-307]. L'algorithme fonctionne comme suit :
L'écriture de l'algorithme dépend de la
structure informatique choisie pour représenter les données;
nous supposons que l'on représente les listes par des
tableaux [19, p. 342]; on pourrait tout aussi bien
utiliser des listes chaînées [34, chap. 12]. Dans
une première version qui est un pseudo-algorithme on fusionne deux
listes triées en une troisième. Ceci a
l'inconvénient de créer des listes en pagaille et par une
transformation de programme on crée la liste fusionnée en place,
moyennant l'utilisation d'une liste auxiliaire [20, §
4.3]; en pratique il suffit de pouvoir fusionner deux listes
triées représentées par des sous-intervalles d'un tableau, ces
sous-intervalles étant contigus de la forme
et
. Dans la procédure Pascal
qui suit ces entiers sont donc les paramètres, le tableau étant
une variable globale.
Ce point technique étant acquis l'écriture de l'algorithme reflète directement la stratégie diviser pour régner.
procedure mergesort(var a:list; i,j:integer);
var m:integer;
begin
if i+1<j then begin
m:= (i+j) div 2;
mergesort(a,i,m);
mergesort(a,m,j);
merge(a,i,m,j);
end
end;
Pour être exhaustif, indiquons une version possible de la fusion.
procedure merge(var a:list; i,j,k:integer);
var m,n,p:integer;
b: list;
begin
m:=i; n:=j; p:=i;
while (m<j) and (n<k) do begin
if a[m]<a[n] then begin b[p]:=a[m]; m:=m+1 end
else begin b[p]:=a[n]; n:=n+1 end;
p:=p+1;
end;
if (m<j) then for n:=m to j-1 do begin b[p]:=a[n]; p:=p+1; end
else for m:=n to k-1 do begin b[p]:=a[m]; p:=p+1; end;
for m:=i to k-1 do a[m]:=b[m];
end;
Le tri rapide emploie aussi la stratégie diviser pour régner. On choisit un élément particulier, par exemple le premier du tableau à trier, puis on partitionne les éléments suivant leur place par rapport à cette clé distinguée; ceci crée deux sous-listes constituées respectivement des éléments plus petits et des éléments plus grands que la clé, auxquelles on va appliquer récursivement le même traitement; la fusion consiste à mettre la clé distinguée à sa bonne place et les deux sous-listes triées respectivement à gauche et à droite de la clé.
Multiplication.
La multiplication d'objets disons structurés fournit une autre
application de la stratégie diviser pour régner [20, chap.
6]. Un entier naturel dont l'écriture en base B est
, ce qui s'énonce aussi
![]()
![]()
![]()
nm=yB2k+(x-y-z)Bk+z.
Bien sûr les produits x, y et z sont calculés suivant la même stratégie. On remarque que l'on a effectué trois multiplications là où l'algorithme naïf en emploie quatre et c'est là que réside l'intérêt de la stratégie diviser pour régner.
La multiplication des polynômes se traite de la même façon;
la mise en
uvre est d'ailleurs plus simple car il n'y a pas de
problème de retenue [34, chap. 36].
Dans le même esprit l'algorithme de Strassen [27, p. 7]
fournit le produit C=AB de deux matrices A et B décomposées
en quatre blocs,
![]()
![]()
![]()
![]()
![]()
![]()
![]()
Géométrie.
L'algorithmique géométrique emploie elle aussi la stratégie
diviser pour régner. Citons par exemple la
recherche de l'enveloppe convexe d'un nuage de points ([14, pp.
145, 158] ou [32, p. 112]) ou la
construction de son diagramme de Voronoï [32, p. 213].
Dans la recherche de l'enveloppe convexe d'une
famille de n points d'un plan, on procède comme suit. On trie
d'abord les points suivant leurs abscisses, ce qui les range en une
liste p1,
, pn. On brise la liste en deux sous-listes de
même longueur p1,
, pk et pk+1,
, pn.
On fabrique récursivement les enveloppes convexes des deux
sous-listes, le cas d'arrêt étant celui où une liste comporte
moins de trois points. Enfin on fusionne les deux enveloppes convexes.
La difficulté réside dans cette dernière opération; pour
l'accomplir on construit le pont supérieur et le pont inférieur
entre les deux enveloppes convexes. On obtient le pont supérieur de
la façon suivante : le point pk est le point le plus à droite
de l'enveloppe de gauche et pk+1 est le point le plus à gauche
de l'enveloppe de droite; on introduit deux variables g et
d, initialisées respectivement aux valeurs pk et pk+1 et
on note D la droite passant par g et d; si le point qui suit
g en parcourant l'enveloppe convexe de gauche dans le sens direct
est au dessus de D on remplace g par son successeur; de même
si le point qui précède d sur l'enveloppe convexe de droite
parcourue dans le sens direct est au dessus de D on remplace d par
son prédecesseur; on itère ces deux actions autant que
possible; à la fin la droite D fournit le pont supérieur. On
procède de même pour le pont inférieur.
| Page précédente : | Introduction |
| Page suivante : | Complexité et récurrences |