logo

Introduzione all'algoritmo 'Dividi e conquista': tutorial sulla struttura dei dati e sugli algoritmi

Dividere e conquistare Algoritmo è una tecnica di problem-solving utilizzata per risolvere i problemi dividendo il problema principale in sottoproblemi, risolvendoli individualmente e poi unendoli per trovare la soluzione al problema originale. In questo articolo, discuteremo di come l'algoritmo Divide and Conquer sia utile e di come possiamo utilizzarlo per risolvere i problemi.



Tabella dei contenuti

Dividere e conquistare Definizione dell'algoritmo:

Algoritmo 'dividi e conquista'. comporta la suddivisione di un problema più grande in sottoproblemi più piccoli, risolvendoli in modo indipendente e quindi combinando le loro soluzioni per risolvere il problema originale. L'idea di base è quella di dividere ricorsivamente il problema in sottoproblemi più piccoli finché non diventano abbastanza semplici da poter essere risolti direttamente. Una volta ottenute le soluzioni ai sottoproblemi, queste vengono poi combinate per produrre la soluzione complessiva.

Funzionamento dell'algoritmo Dividi e Impera:

L’algoritmo “Dividi e conquista” può essere suddiviso in tre fasi: Dividere , Conquistare E Unisci .



1. Dividi:

  • Suddividere il problema originale in sottoproblemi più piccoli.
  • Ogni sottoproblema dovrebbe rappresentare una parte del problema complessivo.
  • L’obiettivo è dividere il problema finché non sia più possibile alcuna ulteriore divisione.

2. Conquista:

  • Risolvi individualmente ciascuno dei sottoproblemi più piccoli.
  • Se un sottoproblema è sufficientemente piccolo (spesso indicato come caso base), lo risolviamo direttamente senza ulteriore ricorsione.
  • L'obiettivo è trovare soluzioni per questi sottoproblemi in modo indipendente.

3. Unisci:

  • Combina i sottoproblemi per ottenere la soluzione finale dell'intero problema.
  • Una volta risolti i sottoproblemi più piccoli, combiniamo ricorsivamente le loro soluzioni per ottenere la soluzione del problema più grande.
  • L'obiettivo è formulare una soluzione per il problema originale unendo i risultati dei sottoproblemi.

Caratteristiche dell'algoritmo Dividi e Impera:

L'algoritmo Divide and Conquer prevede la scomposizione di un problema in parti più piccole e più gestibili, risolvendo ciascuna parte individualmente e quindi combinando le soluzioni per risolvere il problema originale. Le caratteristiche dell’algoritmo Dividi e Conquista sono:

  • Dividere il problema : Il primo passo è suddividere il problema in sottoproblemi più piccoli e più gestibili. Questa divisione può essere eseguita in modo ricorsivo fino a quando i sottoproblemi diventano abbastanza semplici da poter essere risolti direttamente.
  • Indipendenza dei sottoproblemi : Ogni sottoproblema dovrebbe essere indipendente dagli altri, nel senso che la soluzione di un sottoproblema non dipende dalla soluzione di un altro. Ciò consente l'elaborazione parallela o l'esecuzione simultanea di sottoproblemi, che può portare a miglioramenti in termini di efficienza.
  • Conquistare ogni sottoproblema : Una volta divisi, i sottoproblemi vengono risolti individualmente. Ciò può comportare l’applicazione ricorsiva dello stesso approccio divide et impera fino a quando i sottoproblemi diventano abbastanza semplici da essere risolti direttamente, oppure può comportare l’applicazione di un algoritmo o di una tecnica diversa.
  • Combinare soluzioni : Dopo aver risolto i sottoproblemi, le loro soluzioni vengono combinate per ottenere la soluzione del problema originale. Questo passaggio di combinazione dovrebbe essere relativamente efficiente e semplice, poiché le soluzioni ai sottoproblemi dovrebbero essere progettate per adattarsi perfettamente.

Esempi di algoritmo “dividi e conquista”:

1. Trovare l'elemento massimo nell'array:

Possiamo usare l'algoritmo Divide and Conquer per trovare l'elemento massimo nell'array dividendo l'array in due sottoarray di uguali dimensioni, trovando il massimo di queste due metà individuali dividendole nuovamente in due metà più piccole. Questo viene fatto fino a raggiungere i sottoarray di dimensione 1. Dopo aver raggiunto gli elementi, restituiamo l'elemento massimo e combiniamo i sottoarray restituendo il massimo in ciascun sottoarray.



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>ciao) ritorna INT_MIN;  // Se il sottoarray ha un solo elemento, restituisce // l'elemento if (lo == hi) return a[lo];  int metà = (lo + ciao) / 2;  // Ottieni l'elemento massimo dalla metà sinistra int leftMax = findMax(a, lo, mid);  // Ottieni l'elemento massimo dalla metà destra int rightMax = findMax(a, mid + 1, hi);  // Restituisce l'elemento massimo da sinistra e destra // metà ritorno max(leftMax, rightMax); }>
Giava
// 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>ciao) restituisce intero.MIN_VALUE;  // Se il sottoarray ha un solo elemento, restituisce // l'elemento if (lo == hi) return a[lo];  int metà = (lo + ciao) / 2;  // Ottieni l'elemento massimo dalla metà sinistra int leftMax = findMax(a, lo, mid);  // Ottieni l'elemento massimo dalla metà destra int rightMax = findMax(a, mid + 1, hi);  // Restituisce l'elemento massimo dalla metà sinistra e // destra restituisce 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') # Se il sottoarray ha un solo elemento, restituisce l'elemento # if lo == hi: return a[lo] mid = (lo + hi) // 2 # Ottieni il massimo elemento dalla metà sinistra left_max = find_max(a, lo, mid) # Ottieni l'elemento massimo dalla metà destra right_max = find_max(a, mid + 1, hi) # Restituisce l'elemento massimo da sinistra e destra # metà return max (sinistra_max, destra_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>hi) restituisce int.MinValue;  // Se il sottoarray ha un solo elemento, restituisce // l'elemento if (lo == hi) return a[lo];  int metà = (lo + ciao) / 2;  // Ottieni l'elemento massimo dalla metà sinistra int leftMax = FindMax(a, lo, mid);  // Ottieni l'elemento massimo dalla metà destra int rightMax = FindMax(a, mid + 1, hi);  // Restituisce l'elemento massimo dalla metà sinistra e // destra restituisce 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>ciao) restituisce Numero.MIN_VALUE;  // Se il sottoarray ha un solo elemento, restituisce // l'elemento if (lo === hi) return a[lo];  const mid = Math.floor((lo + hi) / 2);  // Ottieni l'elemento massimo dalla metà sinistra const leftMax = findMax(a, lo, mid);  // Ottieni l'elemento massimo dalla metà destra const rightMax = findMax(a, mid + 1, hi);  // Restituisce l'elemento massimo da sinistra e da destra // half return Math.max(leftMax, rightMax); }>

2. Trovare l'elemento minimo nell'array:

Allo stesso modo, possiamo usare l'algoritmo Divide and Conquer per trovare l'elemento minimo nell'array dividendo l'array in due sottoarray di uguali dimensioni, trovando il minimo di queste due metà individuali dividendole nuovamente in due metà più piccole. Questo viene fatto fino a raggiungere i sottoarray di dimensione 1. Dopo aver raggiunto gli elementi, restituiamo l'elemento minimo e combiniamo i sottoarray restituendo il minimo in ciascun sottoarray.

3. Unisci ordinamento:

Possiamo utilizzare l'algoritmo Divide and Conquer per ordinare l'array in ordine ascendente o discendente dividendo l'array in sottoarray più piccoli, ordinando i sottoarray più piccoli e quindi unendo gli array ordinati per ordinare l'array originale.

Analisi della complessità dell'algoritmo “dividi e conquista”:

T(n) = aT(n/b) + f(n), dove n = dimensione dell'input a = numero di sottoproblemi nella ricorsione n/b = dimensione di ciascun sottoproblema. Si presuppone che tutti i sottoproblemi abbiano la stessa dimensione. f(n) = costo del lavoro svolto al di fuori della chiamata ricorsiva, che include il costo della divisione del problema e il costo dell'unione delle soluzioni

Applicazioni dell'algoritmo Dividi e Impera:

Di seguito sono riportati alcuni algoritmi standard che seguono l'algoritmo Divide and Conquer:

  • Ordinamento rapido è un algoritmo di ordinamento che seleziona un elemento pivot e riorganizza gli elementi dell'array in modo che tutti gli elementi più piccoli dell'elemento pivot selezionato si spostino sul lato sinistro del pivot e tutti gli elementi più grandi si spostino sul lato destro. Infine, l'algoritmo ordina ricorsivamente i sottoarray a sinistra e a destra dell'elemento pivot.
  • Unisci ordinamento è anche un algoritmo di ordinamento. L'algoritmo divide l'array in due metà, le ordina ricorsivamente e infine unisce le due metà ordinate.
  • Coppia di punti più vicina Il problema è trovare la coppia di punti più vicina in un insieme di punti nel piano xy. Il problema può essere risolto in tempo O(n^2) calcolando le distanze di ogni coppia di punti e confrontando le distanze per trovare il minimo. L'algoritmo Divide and Conquer risolve il problema in tempo O(N log N).
  • Algoritmo di Strassen è un algoritmo efficiente per moltiplicare due matrici. Un metodo semplice per moltiplicare due matrici richiede 3 cicli annidati ed è O(n^3). L’algoritmo di Strassen moltiplica due matrici in tempo O(n^2.8974).
  • Algoritmo di Cooley-Tukey Fast Fourier Transform (FFT). è l'algoritmo più comune per la FFT. È un algoritmo divide et impera che funziona in tempo O (N log N).
  • Algoritmo Karatsuba per la moltiplicazione veloce esegue la moltiplicazione di due stringhe binarie in O(n1,59) dove n è la lunghezza della stringa binaria.

Vantaggi dell’algoritmo “Dividi e conquista”:

  • Risolvere problemi difficili: La tecnica “divide et impera” è uno strumento per risolvere concettualmente problemi difficili. per esempio. Puzzle della Torre di Hanoi. Richiede un modo per suddividere il problema in sottoproblemi, risolverli tutti come casi individuali e quindi combinare i sottoproblemi al problema originale.
  • Efficienza dell'algoritmo: L'algoritmo divide et impera spesso aiuta nella scoperta di algoritmi efficienti. È la chiave per algoritmi come Quick Sort e Merge Sort e trasformate veloci di Fourier.
  • Parallelismo: Normalmente gli algoritmi Divide and Conquer vengono utilizzati in macchine multiprocessore dotate di sistemi di memoria condivisa dove la comunicazione dei dati tra processori non necessita di essere pianificata in anticipo, poiché sottoproblemi distinti possono essere eseguiti su processori diversi.
  • Accesso alla memoria: Questi algoritmi fanno naturalmente un uso efficiente delle cache di memoria. Poiché i sottoproblemi sono abbastanza piccoli da poter essere risolti nella cache senza utilizzare la memoria principale che è più lenta. Qualsiasi algoritmo che utilizza la cache in modo efficiente è chiamato cache ignaro.

Svantaggi dell’algoritmo “Dividi e Impera”:

  • In testa: Il processo di divisione del problema in sottoproblemi e quindi di combinazione delle soluzioni può richiedere tempo e risorse aggiuntivi. Questo sovraccarico può essere significativo per problemi già relativamente piccoli o che hanno una soluzione semplice.
  • Complessità: Dividere un problema in sottoproblemi più piccoli può aumentare la complessità della soluzione complessiva. Ciò è particolarmente vero quando i sottoproblemi sono interdipendenti e devono essere risolti in un ordine specifico.
  • Difficoltà di implementazione: Alcuni problemi sono difficili da dividere in sottoproblemi più piccoli o richiedono un algoritmo complesso per farlo. In questi casi, può essere difficile implementare una soluzione “divide et impera”.
  • Limitazioni della memoria: Quando si lavora con insiemi di dati di grandi dimensioni, i requisiti di memoria per la memorizzazione dei risultati intermedi dei sottoproblemi possono diventare un fattore limitante.

Domande frequenti (FAQ) sull'algoritmo 'dividi et impera':

1. Cos'è l'algoritmo Dividi e Impera?

Divide and Conquer è una tecnica di problem solving in cui un problema viene suddiviso in sottoproblemi più piccoli e più gestibili. Questi sottoproblemi vengono risolti ricorsivamente e quindi le loro soluzioni vengono combinate per risolvere il problema originale.

2. Quali sono i passaggi chiave coinvolti nell'algoritmo Divide and Conquer?

I passaggi principali sono:

Dividere : suddividere il problema in sottoproblemi più piccoli.

Conquistare : Risolve i sottoproblemi in modo ricorsivo.

Combina : Unisci o combina le soluzioni dei sottoproblemi per ottenere la soluzione del problema originale.

3. Quali sono alcuni esempi di problemi risolti utilizzando Divide and Conquer?

L'algoritmo Divide and Conquer viene utilizzato negli algoritmi di ordinamento come Merge Sort e Quick Sort, trovando la coppia di punti più vicina, l'algoritmo di Strassen, ecc.

lista collegata in Java

4. In che modo Merge Sort utilizza l'approccio Divide and Conquer?

Merge Sort divide la matrice in due metà, ordina ricorsivamente ciascuna metà e quindi unisce le metà ordinate per produrre la matrice ordinata finale.

5. Qual è la complessità temporale degli algoritmi Divide and Conquer?

La complessità temporale varia a seconda del problema specifico e del modo in cui viene implementato. Generalmente, molti algoritmi Divide and Conquer hanno una complessità temporale pari a O(n log n) o migliore.

6. Gli algoritmi Divide and Conquer possono essere parallelizzati?

Sì, gli algoritmi Divide and Conquer sono spesso naturalmente parallelizzabili perché sottoproblemi indipendenti possono essere risolti contemporaneamente. Ciò li rende adatti per ambienti informatici paralleli.

7. Quali sono alcune strategie per scegliere il caso base negli algoritmi Divide and Conquer?

Il caso base dovrebbe essere abbastanza semplice da poter essere risolto direttamente, senza ulteriori divisioni. Viene spesso scelto in base alla dimensione di input più piccola in cui il problema può essere risolto banalmente.

8. Ci sono svantaggi o limitazioni nell'utilizzo di Divide and Conquer?

Anche se Dividi e Impera può portare a soluzioni efficienti per molti problemi, potrebbe non essere adatto a tutti i tipi di problemi. Anche il sovraccarico derivante dalla ricorsione e dalla combinazione di soluzioni può rappresentare un problema per problemi di dimensioni molto grandi.

9. Come si analizza la complessità spaziale degli algoritmi Divide and Conquer?

La complessità dello spazio dipende da fattori come la profondità di ricorsione e lo spazio ausiliario richiesto per combinare le soluzioni. L'analisi della complessità dello spazio implica in genere la considerazione dello spazio utilizzato da ciascuna chiamata ricorsiva.

10. Quali sono alcuni vantaggi comuni dell'algoritmo Divide and Conquer?

L'algoritmo Divide and Conquer presenta numerosi vantaggi. Alcuni di essi includono:

  • Risolvere problemi difficili
  • Efficienza dell'algoritmo
  • Parallelismo
  • Accesso alla memoria

Divide and Conquer è una tecnica algoritmica popolare nell'informatica che prevede la scomposizione di un problema in sottoproblemi più piccoli, la risoluzione di ciascun sottoproblema in modo indipendente e quindi la combinazione delle soluzioni dei sottoproblemi per risolvere il problema originale. L’idea alla base di questa tecnica è quella di dividere un problema in sottoproblemi più piccoli, più gestibili e risolvibili più facilmente.