logo

Introduction à l'algorithme Diviser pour mieux régner – Didacticiels sur la structure des données et l'algorithme

Diviser et conquérir Algorithme est une technique de résolution de problèmes utilisée pour résoudre des problèmes en divisant le problème principal en sous-problèmes, en les résolvant individuellement, puis en les fusionnant pour trouver une solution au problème d'origine. Dans cet article, nous allons expliquer en quoi l'algorithme Divide and Conquer est utile et comment nous pouvons l'utiliser pour résoudre des problèmes.



Table des matières

Diviser et conquérir Définition de l'algorithme :

Algorithme Diviser pour régner implique de diviser un problème plus vaste en sous-problèmes plus petits, de les résoudre indépendamment, puis de combiner leurs solutions pour résoudre le problème d'origine. L’idée de base est de diviser récursivement le problème en sous-problèmes plus petits jusqu’à ce qu’ils deviennent suffisamment simples pour être résolus directement. Une fois les solutions aux sous-problèmes obtenues, elles sont ensuite combinées pour produire la solution globale.

Fonctionnement de l'algorithme Diviser pour régner :

L’algorithme Divide and Conquer peut être divisé en trois étapes : Diviser , Conquérir et Fusionner .



chaîne jsonobjet

1. Divisez :

  • Décomposez le problème initial en sous-problèmes plus petits.
  • Chaque sous-problème doit représenter une partie du problème global.
  • Le but est de diviser le problème jusqu’à ce qu’aucune autre division ne soit possible.

2. Conquérir :

  • Résolvez chacun des petits sous-problèmes individuellement.
  • Si un sous-problème est suffisamment petit (souvent appelé cas de base), nous le résolvons directement sans autre récursion.
  • L’objectif est de trouver des solutions à ces sous-problèmes de manière indépendante.

3. Fusionner :

  • Combinez les sous-problèmes pour obtenir la solution finale de l’ensemble du problème.
  • Une fois les petits sous-problèmes résolus, nous combinons récursivement leurs solutions pour obtenir la solution d’un problème plus vaste.
  • Le but est de formuler une solution au problème initial en fusionnant les résultats des sous-problèmes.

Caractéristiques de l'algorithme Diviser pour régner :

L’algorithme Divide and Conquer consiste à décomposer un problème en parties plus petites et plus faciles à gérer, à résoudre chaque partie individuellement, puis à combiner les solutions pour résoudre le problème d’origine. Les caractéristiques de l’algorithme Divide and Conquer sont :

  • Diviser le problème : La première étape consiste à diviser le problème en sous-problèmes plus petits et plus gérables. Cette division peut être effectuée de manière récursive jusqu'à ce que les sous-problèmes deviennent suffisamment simples pour être résolus directement.
  • Indépendance des sous-problèmes : Chaque sous-problème doit être indépendant des autres, ce qui signifie que la résolution d'un sous-problème ne dépend pas de la solution d'un autre. Cela permet un traitement parallèle ou une exécution simultanée de sous-problèmes, ce qui peut conduire à des gains d'efficacité.
  • Conquérir chaque sous-problème : Une fois divisés, les sous-problèmes sont résolus individuellement. Cela peut impliquer d'appliquer la même approche diviser pour régner de manière récursive jusqu'à ce que les sous-problèmes deviennent suffisamment simples pour être résolus directement, ou cela peut impliquer l'application d'un algorithme ou d'une technique différente.
  • Combiner les solutions : Après avoir résolu les sous-problèmes, leurs solutions sont combinées pour obtenir la solution du problème initial. Cette étape de combinaison devrait être relativement efficace et simple, car les solutions aux sous-problèmes doivent être conçues pour s’emboîter de manière transparente.

Exemples d’algorithme diviser pour régner :

1. Recherche de l'élément maximum dans le tableau :

Nous pouvons utiliser l'algorithme Divide and Conquer pour trouver l'élément maximum dans le tableau en divisant le tableau en deux sous-tableaux de taille égale, en trouvant le maximum de ces deux moitiés individuelles en les divisant à nouveau en deux moitiés plus petites. Ceci est fait jusqu'à ce que nous atteignions des sous-tableaux de taille 1. Après avoir atteint les éléments, nous renvoyons l'élément maximum et combinons les sous-tableaux en renvoyant le maximum dans chaque sous-tableau.



C++
// function to find the maximum no. // in a given array. int findMax(int a[], int lo, int hi) {  // If lo becomes greater than hi, then return minimum  // integer possible  if (lo>salut) renvoie INT_MIN ;  // Si le sous-tableau n'a qu'un seul élément, renvoie l'élément // if (lo == hi) return a[lo];  int mid = (lo + hi) / 2;  // Récupère le maximum d'éléments de la moitié gauche int leftMax = findMax(a, lo, mid);  // Récupère le maximum d'éléments de la moitié droite int rightMax = findMax(a, mid + 1, hi);  // Renvoie le maximum d'éléments de gauche et de droite // moitié return max(leftMax, rightMax); }>
Java
// Function to find the maximum number // in a given array. static int findMax(int[] a, int lo, int hi) {  // If lo becomes greater than hi, then return  // minimum integer possible  if (lo>salut) renvoie Integer.MIN_VALUE ;  // Si le sous-tableau n'a qu'un seul élément, renvoie l'élément // if (lo == hi) return a[lo];  int mid = (lo + hi) / 2;  // Récupère le maximum d'éléments de la moitié gauche int leftMax = findMax(a, lo, mid);  // Récupère le maximum d'éléments de la moitié droite int rightMax = findMax(a, mid + 1, hi);  // Renvoie l'élément maximum des moitiés gauche et // droite return Math.max(leftMax, rightMax); }>
Python3
# Function to find the maximum number # in a given array. def find_max(a, lo, hi): # If lo becomes greater than hi, then return minimum # integer possible if lo>hi: return float('-inf') # Si le sous-tableau n'a qu'un seul élément, renvoie l'élément # if lo == hi: return a[lo] mid = (lo + hi) // 2 # Obtenez le maximum élément de la moitié gauche left_max = find_max(a, lo, mid) # Récupère le maximum d'éléments de la moitié droite right_max = find_max(a, mid + 1, hi) # Renvoie le maximum d'éléments de gauche et de droite # half return max (gauche_max, droite_max)>
C#
// Function to find the maximum number // in a given array. static int FindMax(int[] a, int lo, int hi) {  // If lo becomes greater than hi, then return  // minimum integer possible  if (lo>salut) retourner int.MinValue ;  // Si le sous-tableau n'a qu'un seul élément, renvoie l'élément // if (lo == hi) return a[lo];  int mid = (lo + hi) / 2;  // Récupère le maximum d'éléments de la moitié gauche int leftMax = FindMax(a, lo, mid);  // Récupère le maximum d'éléments de la moitié droite int rightMax = FindMax(a, mid + 1, hi);  // Renvoie l'élément maximum des moitiés gauche et // droite return Math.Max(leftMax, rightMax); }>
Javascript
// Function to find the maximum number // in a given array. function findMax(a, lo, hi) {  // If lo becomes greater than hi, then return minimum  // integer possible  if (lo>salut) renvoie Number.MIN_VALUE ;  // Si le sous-tableau n'a qu'un seul élément, renvoie l'élément // if (lo === hi) return a[lo];  const mid = Math.floor((lo + hi) / 2);  // Récupère l'élément maximum de la moitié gauche const leftMax = findMax(a, lo, mid);  // Récupère l'élément maximum de la moitié droite const rightMax = findMax(a, mid + 1, hi);  // Renvoie l'élément maximum de gauche et de droite // moitié return Math.max(leftMax, rightMax); }>

2. Recherche de l'élément minimum dans le tableau :

De même, nous pouvons utiliser l'algorithme Divide and Conquer pour trouver l'élément minimum dans le tableau en divisant le tableau en deux sous-tableaux de taille égale, en trouvant le minimum de ces deux moitiés individuelles en les divisant à nouveau en deux moitiés plus petites. Ceci est fait jusqu'à ce que nous atteignions des sous-tableaux de taille 1. Après avoir atteint les éléments, nous renvoyons l'élément minimum et combinons les sous-tableaux en renvoyant le minimum dans chaque sous-tableau.

nombre à chaîne java

3. Tri par fusion:

Nous pouvons utiliser l'algorithme Divide and Conquer pour trier le tableau par ordre croissant ou décroissant en divisant le tableau en sous-tableaux plus petits, en triant les sous-tableaux plus petits, puis en fusionnant les tableaux triés pour trier le tableau d'origine.

Analyse de la complexité de l'algorithme Diviser pour régner :

T(n) = aT(n/b) + f(n), où n = taille de l'entrée a = nombre de sous-problèmes dans la récursion n/b = taille de chaque sous-problème. Tous les sous-problèmes sont supposés avoir la même taille. f(n) = coût du travail effectué en dehors de l'appel récursif, qui comprend le coût de division du problème et le coût de fusion des solutions

Applications de l’algorithme Diviser pour régner :

Voici quelques algorithmes standards qui suivent l’algorithme Divide and Conquer :

  • Tri rapide est un algorithme de tri qui sélectionne un élément pivot et réorganise les éléments du tableau de sorte que tous les éléments plus petits que l'élément pivot sélectionné se déplacent vers le côté gauche du pivot et que tous les éléments plus grands se déplacent vers le côté droit. Enfin, l'algorithme trie de manière récursive les sous-tableaux à gauche et à droite de l'élément pivot.
  • Tri par fusion est aussi un algorithme de tri. L'algorithme divise le tableau en deux moitiés, les trie de manière récursive et fusionne finalement les deux moitiés triées.
  • Paire de points la plus proche Le problème est de trouver la paire de points la plus proche dans un ensemble de points dans le plan xy. Le problème peut être résolu en un temps O(n^2) en calculant les distances de chaque paire de points et en comparant les distances pour trouver le minimum. L'algorithme Divide and Conquer résout le problème en un temps O (N log N).
  • L'algorithme de Strassen est un algorithme efficace pour multiplier deux matrices. Une méthode simple pour multiplier deux matrices nécessite 3 boucles imbriquées et est O(n^3). L'algorithme de Strassen multiplie deux matrices en un temps O(n^2,8974).
  • Algorithme de transformation de Fourier rapide (FFT) de Cooley – Tukey est l'algorithme le plus courant pour la FFT. Il s'agit d'un algorithme diviser pour régner qui fonctionne en temps O (N log N).
  • Algorithme Karatsuba pour une multiplication rapide fait la multiplication de deux chaînes binaires dans O(n1,59) où n est la longueur de la chaîne binaire.

Avantages de l’algorithme Diviser pour régner :

  • Résoudre des problèmes difficiles : La technique Diviser pour mieux régner est un outil permettant de résoudre conceptuellement des problèmes difficiles. par exemple. Puzzle Tour de Hanoï. Cela nécessite un moyen de diviser le problème en sous-problèmes, de les résoudre tous en tant que cas individuels, puis de combiner les sous-problèmes au problème d'origine.
  • Efficacité de l'algorithme : L’algorithme diviser pour régner aide souvent à la découverte d’algorithmes efficaces. C'est la clé d'algorithmes tels que le tri rapide et le tri par fusion, ainsi que des transformations de Fourier rapides.
  • Parallélisme: Normalement, les algorithmes Divide and Conquer sont utilisés dans les machines multiprocesseurs dotées de systèmes de mémoire partagée où la communication des données entre processeurs n'a pas besoin d'être planifiée à l'avance, car des sous-problèmes distincts peuvent être exécutés sur différents processeurs.
  • Accès à la mémoire : Ces algorithmes utilisent naturellement efficacement les caches mémoire. Étant donné que les sous-problèmes sont suffisamment petits pour être résolus dans le cache sans utiliser la mémoire principale, qui est plus lente. Tout algorithme qui utilise efficacement le cache est appelé inconscient du cache.

Inconvénients de l’algorithme Diviser pour régner :

  • Aérien: Le processus consistant à diviser le problème en sous-problèmes puis à combiner les solutions peut nécessiter du temps et des ressources supplémentaires. Cette surcharge peut être importante pour des problèmes déjà relativement mineurs ou ayant une solution simple.
  • Complexité: Diviser un problème en sous-problèmes plus petits peut augmenter la complexité de la solution globale. Cela est particulièrement vrai lorsque les sous-problèmes sont interdépendants et doivent être résolus dans un ordre précis.
  • Difficulté de mise en œuvre : Certains problèmes sont difficiles à diviser en sous-problèmes plus petits ou nécessitent pour ce faire un algorithme complexe. Dans ces cas-là, il peut s’avérer difficile de mettre en œuvre une solution « diviser pour mieux régner ».
  • Limites de mémoire : Lorsque vous travaillez avec de grands ensembles de données, les besoins en mémoire pour stocker les résultats intermédiaires des sous-problèmes peuvent devenir un facteur limitant.

Foire aux questions (FAQ) sur l’algorithme Diviser pour régner :

1. Qu'est-ce que l'algorithme Divide and Conquer ?

Divide and Conquer est une technique de résolution de problèmes dans laquelle un problème est divisé en sous-problèmes plus petits et plus gérables. Ces sous-problèmes sont résolus de manière récursive, puis leurs solutions sont combinées pour résoudre le problème initial.

2. Quelles sont les étapes clés impliquées dans l’algorithme Divide and Conquer ?

Les principales étapes sont :

Diviser : Divisez le problème en sous-problèmes plus petits.

Conquérir : Résolvez les sous-problèmes de manière récursive.

Combiner : Fusionner ou combiner les solutions des sous-problèmes pour obtenir la solution du problème d'origine.

3. Quels sont quelques exemples de problèmes résolus grâce à Divide and Conquer ?

L'algorithme Divide and Conquer est utilisé dans les algorithmes de tri tels que le tri par fusion et le tri rapide, la recherche de la paire de points la plus proche, l'algorithme de Strassen, etc.

4. Comment Merge Sort utilise-t-il l'approche Divide and Conquer ?

Merge Sort divise le tableau en deux moitiés, trie chaque moitié de manière récursive, puis fusionne les moitiés triées pour produire le tableau trié final.

différence entre un tigre et un lion

5. Quelle est la complexité temporelle des algorithmes Divide and Conquer ?

La complexité temporelle varie en fonction du problème spécifique et de la manière dont il est mis en œuvre. Généralement, de nombreux algorithmes Divide and Conquer ont une complexité temporelle de O (n log n) ou mieux.

6. Les algorithmes Divide and Conquer peuvent-ils être parallélisés ?

Oui, les algorithmes Divide and Conquer sont souvent naturellement parallélisables car des sous-problèmes indépendants peuvent être résolus simultanément. Cela les rend adaptés aux environnements informatiques parallèles.

7. Quelles sont quelques stratégies pour choisir le cas de base dans les algorithmes Divide and Conquer ?

Le cas de base doit être suffisamment simple pour être résolu directement, sans autre division. Il est souvent choisi en fonction de la plus petite taille d’entrée où le problème peut être résolu de manière triviale.

8. Y a-t-il des inconvénients ou des limites à l’utilisation de Divide and Conquer ?

Bien que diviser pour mieux régner puisse conduire à des solutions efficaces à de nombreux problèmes, il se peut qu’il ne soit pas adapté à tous les types de problèmes. Les frais généraux liés à la récursivité et à la combinaison de solutions peuvent également constituer un problème pour des problèmes de très grande taille.

9. Comment analysez-vous la complexité spatiale des algorithmes Divide and Conquer ?

La complexité de l'espace dépend de facteurs tels que la profondeur de récursion et l'espace auxiliaire requis pour combiner des solutions. L'analyse de la complexité de l'espace implique généralement de considérer l'espace utilisé par chaque appel récursif.

10. Quels sont les avantages courants de l’algorithme Divide and Conquer ?

L’algorithme Divide and Conquer présente de nombreux avantages. Certains d'entre eux incluent :

  • Résoudre des problèmes difficiles
  • Efficacité de l'algorithme
  • Parallélisme
  • Accès à la mémoire

Divide and Conquer est une technique algorithmique populaire en informatique qui consiste à décomposer un problème en sous-problèmes plus petits, à résoudre chaque sous-problème indépendamment, puis à combiner les solutions des sous-problèmes pour résoudre le problème d'origine. L’idée de base de cette technique est de diviser un problème en sous-problèmes plus petits et plus gérables qui peuvent être résolus plus facilement.