1
Chapitre 4 : La Méthode Diviser et Régner
1. Introduction La stratégie diviser-et-régner consiste :
a. à briser un problème en sous-problèmes plus simples de même type,
b. à trouver d’une manière indépendante la solution de chacun de ces sous-problèmes
c. ensuite à 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.
Cette approche conduit, de façon naturelle (mais pas nécessairement), à un algorithme récursif.
Seulement, la question qui pourrait se poser est de savoir comment obtenir la solution des sous-
problèmes. La réponse est d’appliquer la même approche diviser-pour-regner descendante et ce,
jusqu’à ce que le problème deviennent trivial.
Il est utile de signaler que pour que l’approche diviser-et-regner puisse conduire à un algorithme
récursif, il est nécessaire que les sous-problèmes résultants soient de même type au problème
initial. Si ce n’est pas le cas, on peut quand même considérer qu’on utilise une approche diviser-
et-régner, mais sans récursivité. Le graphe résultant de cette technique est comme suit :
2
Problème
P1
Sous-problème
P11
Sous-problème
P1k
Sous-problème
P12
Sous-problème
P111
Sous-problème
P112
Sous-problème
P1k1 Sous-problème
P1k2
Sous-soulition
P11
Sous-solution
P1k
Solution
problème P1
3
2. Déterminer le moment de cesser les appels recursifs
Dans la mise en oeuvre directe de la stratégie diviser-et-régner avec récursivité, on cesse les appels récursifs
(la décomposition en sous-problèmes) lorsque le problème à résoudre est vraiment trivial, c’est-à-dire qu’il ne
peut plus être décomposé ou qu’il n’est plus intéressant de le décomposer encore (cela est vrai pour les
problèmes typiquement de taille 1).
En théorie les surcoûts (overhead) associés à la gestion des appels récursifs (par exemple, l’allocation et copie
des arguments de la fonction dans la pile) peuvent être ignores. En pratique, ces surcoûts peuvent devenir
significatifs et il peut devenir plus efficace, à partir d’une certaine taille de problème, d’utiliser une approche
asymptotiquement moins efficace, mais avec un coefficient plus faible au niveau des surcoûts. La stratégie
diviser-et-régner avec seuil (avec coupure) devient donc, en gros, la suivante (en supposant une
décomposition dichotomique) :
L’algorithme générique de diviser-etrégner peut être résumé come suit :
Solution resoudre_dpr( Probleme p )
{
if (taille(p) <= TAILLE_MIN)
return( resoudre_algo_simple(p) ); // Solution non-récursive
else {
// décompser le problème p en sous-problèmes p1, p2, …, pk;
(p1, p2, …pk) = decomposer(p);
// Appels récursifs
solution s1 = resoudre_dpr(p1);
solution s2 = resoudre_dpr(p2);
// etc …
solution sk = resoudre_dpr(pk);
return( combiner(p, p1, p2,.., pk) );
}
La sélection de la valeur seuil (threshold) à partir de laquelle la récursivité doit se terminer
dépend de nombreux facteurs, comme par exemple :
Mise en oeuvre exact de l’algorithme.
Langage et compilateur utilises.
Machine et système d’exploitation sur lesquels s’exécute le programme.
Données sur lesquelles le programme est exécuté.
En d’autres mots, l’analyse théorique de l’algorithme ne suffit plus. On doit plutôt utiliser diverses techniques
et outils plus pratiques, par exemple, on pourrait exécuter le programme avec différentes données et mesurer
son temps d’exécution, utiliser l’outil profile (sur Unix/Linux) pour déterminer les fonctions et procédures les
plus fréquemment appelées et déterminer les points chauds du programme, etc.
4
3. Diviser et régner et la récursivité : Pour que l’approche diviser-et-régner avec récursivité
conduise à une solution efficace, il ne faut pas que l’une ou l’autre des conditions suivantes
survienne :
1. Un problème de taille n est décomposé en deux ou plusieurs sous-problèmes eux- même
de taille presque n (par exemple de taille n 1).
2. Un problème de taille n est décomposé en n sous-problèmes de taille n/c (pour une
constante c 2). Rappelons aussi que l’approche diviser-et-régner avec recursivité ne
peut être utilisée que si les sous-problèmes sont de même type que le problème initial (par
exemple, le tri d’un tableau se fait en triant ses sous-tableaux). Toutefois, dans de
nombreux cas, on peut dire qu’une approche diviser-pour-regner est utilisée et ce, même
si aucune récursivité n’est nécessaire.
Dans le reste de ce chapitre, il sera question de l’application de cette méthode sur des exemples
divers afin de mieux l’apprécier et voir également comment approcher la résolution d’un
problème d’une manière récursive
4. Applications
4.1. Problème de recherche binaire : le problème de la recherche dichotomique consiste à
rechercher un élément dans un tableau de n éléments, procédant de la manière suivante :
1. on partitionne le tableau en deux parties égales
2. si l‘élément du milieu est celui qu’on cherche, on arrête la recherche
3. sinon, si l‘élément du milieu est supérieur à celui qu’on cherche, alors, comme le tableau
est déjà trié, ce dernier ne peut être que dans la partie gauche de l’élément du milieu
4. autrement l‘élément du milieu est inférieur supérieur à celui qu’on cherche. Dans ce cas,
ce dernier ne peut être que dans la partie droite de l’élément du milieu.
Le cas de base est celui où l’espace de recherche est nul.
Remarque : Nous avons discuté, dans le premier chapitre, une autre méthode pour résoudre ce
problème : la méthode séquentielle. Cette méthode ignore le fait que les éléments du tableau sont
déjà triées. Elle consiste donc à balayer le tableau du début à la fin jusqu’à éventuellement
trouver l’élément en question. Nous avons vu que la complexité de cette méthode, dans le pire
cas et cas moyen, est en O(n).
Implantation
int recherche(int *tab, int c,s,u){
if (sup < inf)
return(‘erreur’)
else {
5
milieu = (s-u+1) div 2;
if (c = = tab[milieu])
return(milieu);
else if (c < tab[milieu])
return( recherche(tab, c, milieu –1,u);
else return( recherché(tab,c,s,milieu+1);
}
Complexité: Voyons de plus prés le pire cas: si le paramètre n est pair, il y a respectivement n/2
éléments précédant et (n/2 –1) éléments suivant l’élément du milieu. En revanche, si n est impair,
il a (n-1)/2 éléments précédant et suivant l’élément du milieu. Autrement dit, dans le pire,
l’espace de recherche est réduit à chaque itération à
2/n éléments.
Si t(n) représente la complexité , alors nous avons :

>+
=
=1,2/
1;1
)( nbnt
n
nt
On a vu au chapitre 2 que la solution de cette équation est :
bnnt
+
=
log)(
Concernant la complexité en moyenne, en principe, nous l’avons discutée lors du chapitre 2 et
des travaux dirigés. Je vous suggère de la refaire tout maintenant.
4.2.Problèmes de tri
Dans cette section, deux méthode de tri sont présentées pour illustrer la technique de diviser-et-
régner. Rappelons, avant, la définition du problème de tri.
Définition: Le problème de tri consiste à ordonner un ensemble d’éléments dans un ordre
croissant ou décroissant selon une clef propre à ces éléments muni d’un ordre total.
4.2.1. Le tri par fusion Cet algorithme fournit un exemple clair de cette stratégie. L'algorithme
fonctionne comme suit :
- on partitionne la liste en deux demi-listes;
- on trie chaque demi-liste;
- on fusionne les deux demi-listes triées.
Le cas de base de l'algorithme est celui où la liste à trier ne comporte qu'une clé.
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. On pourrait tout aussi
bien utiliser des listes chaînées. Dans une première version qui est un pseudo-algorithme on
1 / 20 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !