Merge sort: differenze tra le versioni
Contenuto cancellato Contenuto aggiunto
riscrivo didascalia |
corretto errore nella notazione della complessità temporale dell'algoritmo. Etichette: Modifica da mobile Modifica da web per mobile |
||
| (84 versioni intermedie di 57 utenti non mostrate) | |||
Riga 1:
{{F|programmazione|aprile 2012}}
{{Algoritmo
| |immagine = Merge-sort-example-300px.gif
|didascalia = Esempio di merge sort con una lista di numeri casuali. Innanzitutto, si divide l'elenco nell'unità più piccola (1 elemento), quindi si confronta ogni elemento con l'elenco adiacente per ordinare e unire i due elenchi adiacenti. Infine, tutti gli elementi vengono ordinati e uniti.
|
|
|
|
|
|
}}
Il '''merge sort''' è un [[algoritmo di ordinamento]] basato su confronti che utilizza un processo di risoluzione [[Algoritmo ricorsivo|ricorsivo]], sfruttando la tecnica del [[Divide et impera (informatica)|Divide et Impera]], che consiste nella suddivisione del problema in sottoproblemi della stessa natura di dimensione via via più piccola. Fu inventato da [[John von Neumann]] nel [[1945]]. Una descrizione dettagliata e un'analisi della versione bottom-up dell'algoritmo apparve in un articolo di Goldstine e Neumann già nel 1948.
== Descrizione dell'algoritmo ==
Concettualmente, l'algoritmo funziona nel seguente modo:
# Se la sequenza da ordinare ha lunghezza 0 oppure 1, è già ordinata. Altrimenti:
# La sequenza viene divisa (''divide'') in due metà (se la sequenza contiene un numero dispari di elementi, viene divisa in due sottosequenze di cui la prima ha un elemento in più della seconda)
# Ognuna di queste sottosequenze viene ordinata, applicando [[Algoritmo ricorsivo|ricorsivamente]] l'algoritmo (''impera'')
# Le due sottosequenze ordinate vengono fuse (''combina''). Per fare questo, si estrae ripetutamente il minimo delle due sottosequenze e lo si pone nella sequenza in uscita, che risulterà ordinata
=== Esempio di funzionamento ===
[[File:MergeSort 2.gif|thumb|upright=2.2|Simulazione del merge sort in esecuzione su un array]]
Supponendo di dover ordinare la sequenza [10 3 15 2 1 4 9 0], l'algoritmo procede ricorsivamente dividendola in metà successive, fino ad arrivare agli elementi
[10] [3] [15] [2] [1] [4] [9] [0]
A questo punto si fondono (merge) in maniera ordinata gli elementi, riunendoli in coppie:
[3 10] [2 15] [1 4] [0 9]
Al passo successivo, si fondono le coppie di array di due elementi:
Infine, fondendo le due sequenze di quattro elementi, si ottiene la sequenza ordinata:
[0 1 2 3 4 9 10 15]
L'esecuzione ricorsiva all'interno del calcolatore non avviene nell'ordine descritto sopra. Tuttavia, si è formulato l'esempio in questo modo per renderlo più comprensibile.
=== Implementazione ===
[[File:Merge sort algorithm diagram2.JPG|thumb|Raffigurazione grafica delle versioni iterativa (bottom-up) e ricorsiva (top-down) dell'algoritmo]]
L'algoritmo può essere implementato fondamentalmente tramite due tecniche:
# '''Top-Down''', che è quella presentata in questa pagina. Opera da un insieme <math>A</math> e lo divide in sotto insiemi <math>(A_1, A_2)</math> fino ad arrivare all'insieme contenente un solo elemento, per poi riunire le parti scomposte;
# '''Bottom-Up''', che consiste nel considerare l'insieme <math>A</math> come composto da un vettore di <math>n</math> sequenze. Ad ogni passo vengono fuse due sequenze.
Una possibile implementazione dell'algoritmo in forma di [[pseudocodice]] tramite una tecnica top-down è la seguente:
'''function''' mergesort (a[], left, right)
'''if''' left < right '''then'''
center ← (left + right) / 2
mergesort(a, left, center)
mergesort(a, center+1, right)
merge(a, left, center, right)
Una possibile implementazione della funzione merge (unione di due sottosequenze ordinate) è la seguente:
'''function''' merge (a[], left, center, right)
i ← left
j ← center + 1
k ← 0
b ← array temp size= right-left+1
'''while''' i ≤ center '''and''' j ≤ right '''do'''
'''if''' a[i] ≤ a[j] '''then'''
b[k] ← a[i]
i ← i + 1
k ← k + 1
j ← j + 1
k ← k + 1
'''end while'''
'''while''' i ≤ center '''do'''
b[k] ← a[i]
i ← i + 1
k ← k + 1
'''end while'''
'''while''' j ≤ right '''do'''
b[k] ← a[j]
j ← j + 1
k ← k + 1
'''end while'''
== Analisi ==
L'algoritmo Merge Sort, per ordinare una sequenza di <math>n</math> oggetti, ha complessità temporale <math>T(n) = \Theta(n\log n)</math> sia nel caso medio che nel caso pessimo. Infatti:
* la funzione merge qui presentata ha complessità temporale <math>\Theta(n)</math>
* mergesort richiama se stessa due volte, e ogni volta su (circa) metà della sequenza in input
Da questo segue che il tempo di esecuzione dell'algoritmo è dato dalla ricorrenza:
<math>T(n) = 2T\left(\frac{n}{2}\right)+ \Theta(n)</math>
Esistono implementazioni più efficienti della procedura merge, che hanno nel caso migliore complessità <math>O(1)</math>. Infatti, se i due array da fondere sono già ordinati, è sufficiente confrontare l'ultimo elemento del primo array con il primo elemento del secondo array per sapere che si può fonderli senza effettuare ulteriori confronti. Per cui si può implementare l'algoritmo mergesort in modo che abbia complessità O(nlogn) nel caso peggiore, e O(n) nel caso migliore, cioè quando l'array è già ordinato.
== Bibliografia ==
* {{Cita libro|autore=Thomas H. Cormen|wkautore=Thomas H. Cormen|autore2=Charles Eric Leiserson|autore3=Ronald Linn Rivest|wkautore3=Ronald Rivest|autore4=Clifford Stein|titolo=[[Introduzione agli algoritmi|Introduction to algorithms]]|edizione=3|data=2009|editore=MIT Press|ISBN=978-0-262-53305-8}}
== Altri progetti ==
{{interprogetto|b=Implementazioni di algoritmi/Merge sort|b_oggetto=implementazioni|b_preposizione=
== Collegamenti esterni ==
* {{Collegamenti esterni}}
{{Ordinamento}}
{{Portale|informatica}}
[[Categoria:Algoritmi di ordinamento]]
| |||