Ordinamento 2: merge sort e quicksort
Ordinare un milione di valori confrontando ogni coppia richiede circa 500 miliardi di confronti; al merge sort ne servono circa 20 milioni.
Dividi il problema, risolvi le metà
I metodi dell'unità precedente lavorano su tutta la lista insieme e lo pagano con circa n² confronti. I due metodi di questa unità seguono un piano diverso, chiamato divide et impera. Dividi la lista in parti più piccole, ordina ogni parte con lo stesso metodo e poi unisci le parti ordinate. La divisione continua finché una parte ha un solo valore o nessuno, e una lista di un solo valore è già ordinata. Poiché il metodo richiama sé stesso su liste più piccole, è ricorsivo (l'unità 6 esamina la ricorsione nel dettaglio).
Merge sort: il lavoro sta nella fusione
Il merge sort taglia la lista a metà, ordina la metà sinistra, ordina la metà destra e fonde le due metà ordinate in una sola. La parte ingegnosa è la fusione. Due liste ordinate si possono unire guardando solo i loro primi valori. Confronta i due valori in testa, scrivi il più piccolo e vai oltre. Ripeti finché una lista è vuota, poi copia ciò che resta dell'altra. Fondere [1, 4, 7] e [2, 3, 8] dà 1 (1 contro 2), 2 (4 contro 2), 3 (4 contro 3), 4 (4 contro 8), 7 (7 contro 8), e poi si copia 8: 5 confronti per 6 valori. Una fusione di due liste con n valori in tutto non richiede mai più di n − 1 confronti.
function merge(left, right) {
const out = [];
let i = 0, j = 0;
while (i < left.length && j < right.length) {
if (right[j] < left[i]) out.push(right[j++]);
else out.push(left[i++]);
}
return out.concat(left.slice(i), right.slice(j));
}
function mergeSort(a) {
if (a.length <= 1) return a; // già ordinata
const mid = Math.floor(a.length / 2);
return merge(mergeSort(a.slice(0, mid)), mergeSort(a.slice(mid)));
}Perché è veloce? Immagina i dimezzamenti come livelli. Una lista di 8 valori si divide in 2 liste da 4, poi in 4 liste da 2, poi in 8 liste da 1: tre livelli, perché 8 si può dimezzare 3 volte. A ogni livello, tutte le fusioni insieme toccano ogni valore una volta, quindi un livello costa al massimo circa n confronti. Con log₂ n livelli il totale è circa n log₂ n. Per un milione di valori sono circa 20 milioni di confronti, contro circa 500 miliardi per i metodi che confrontano coppia per coppia. Divisa in [38, 27, 43, 3] e [9, 82, 10], come nel laboratorio, la lista [38, 27, 43, 3, 9, 82, 10] richiede 14 confronti; il codice qui sopra la divide in 3 e 4 e ne richiede 13.
Il prezzo è la memoria. La fusione ha bisogno di un posto dove scrivere il risultato, quindi il merge sort usa una seconda lista grande quanto l'input. Il merge sort è anche stabile: i valori che risultano uguali nel confronto mantengono il loro ordine originale, perché quando i due valori in testa sono uguali la fusione prende dalla lista sinistra. Questo conta quando ordini una tabella per una colonna dopo l'altra, per esempio per città e poi per nome.
Trascina per ruotare. Scorri o avvicina le dita per lo zoom.
Quicksort: dividi attorno a un pivot
Il quicksort divide la lista in un altro modo. Sceglie un valore, il pivot, e risistema la lista in modo che tutto ciò che è più piccolo del pivot venga prima e tutto il resto dopo. Questo passo si chiama partizione. Ora il pivot è al suo posto definitivo, e le due parti si possono ordinare separatamente con lo stesso metodo. Dopo non serve nessuna fusione, perché ogni valore a sinistra è già più piccolo di ogni valore a destra.
Il laboratorio usa una versione comune nei manuali che prende come pivot l'ultimo valore di ogni parte. Su [5, 1, 4, 2, 8] il pivot 8 viene confrontato con gli altri quattro valori, tutti più piccoli, quindi 8 resta in fondo. La parte successiva [5, 1, 4, 2] usa il pivot 2: solo 1 è più piccolo, quindi dopo due scambi la lista è [1, 2, 4, 5, 8]. Un altro confronto sistema [4, 5]. In tutto: 8 confronti e 2 scambi.
Quando il pivot cade vicino al centro, ogni divisione dimezza il problema e il quicksort fa circa n log₂ n confronti, come il merge sort. Inoltre lavora dentro la lista originale, senza una seconda copia. Ma un pivot sbagliato fa male. Se la lista è già ordinata e il pivot è sempre l'ultimo valore, ogni divisione stacca un solo valore, e il quicksort ricade a circa n²/2 confronti: 10 per [1, 2, 3, 4, 5], gli stessi del selection sort. Le librerie reali evitano il problema scegliendo il pivot con più cura, per esempio a caso o come valore di mezzo fra tre campioni.
| Metodo | Confronti | Memoria aggiuntiva |
|---|---|---|
| Insertion sort | di solito circa n²/4, nel caso peggiore circa n²/2 | nessuna; stabile |
| Merge sort | circa n log₂ n, sempre | una seconda lista di n valori; stabile |
| Quicksort | di solito circa n log₂ n, nel caso peggiore circa n²/2 (pivot sbagliati) | poca; le versioni usuali non sono stabili |
| divide et impera | Dividere un problema, risolvere le parti allo stesso modo, unire i risultati |
| fusione (merge) | Unire due liste ordinate prendendo ogni volta il più piccolo dei valori in testa |
| merge sort | Dimezza, ordina ogni metà, fondi: circa n log₂ n confronti |
| pivot | Il valore attorno a cui il quicksort divide la lista |
| partizione | Risistemare la lista in modo che i valori più piccoli stiano prima del pivot e gli altri dopo |
| quicksort | Partiziona attorno a un pivot, poi ordina ciascuna parte |
| ordinamento stabile | I valori uguali mantengono il loro ordine originale |
| sul posto (in place) | Ordina dentro la lista originale con poca memoria aggiuntiva |
- Quanti confronti servono per fondere [1, 4, 7] e [2, 3, 8]?
- Quanti confronti servono per fondere [1, 2, 3] e [4, 5, 6]?
- Una lista di 16 valori viene dimezzata finché ogni parte ha un solo valore. Quanti livelli di dimezzamento ci sono?
- Più o meno quanti confronti fa il merge sort su un milione di valori?
- circa 20
- circa 20 milioni
- circa 500 miliardi
- esattamente un milione
- Dopo la partizione, dove si trova il pivot?
- Nella sua posizione definitiva nella lista ordinata
- All'inizio
- In fondo
- In un posto qualsiasi; si sposterà ancora
- Il quicksort con l'ultimo valore come pivot viene eseguito sulla lista già ordinata [1, 2, 3, 4, 5]. Quanti confronti fa?
- Quale metodo ha bisogno di una seconda lista grande quanto l'input?
- Merge sort
- Quicksort
- Insertion sort
- Chi propose il merge sort nel 1945?
- Tony Hoare
- John von Neumann
- Ada Lovelace
- Euclide
- Quale problema portò Tony Hoare al quicksort?
- Ordinare le parole di una frase per un dizionario su nastro magnetico
- Ordinare i libri di una biblioteca
- Classificare le pagine web
- Ordinare gli assegni di una banca
- Perché il merge sort si dice stabile?
- I valori uguali mantengono il loro ordine originale
- Non si blocca mai
- Richiede sempre lo stesso tempo
- Non usa memoria aggiuntiva
- Qual è il minimo numero di confronti nel caso peggiore per un qualsiasi ordinamento per confronti di 10 valori (log₂ 10!, arrotondato per eccesso)?
- Divide et impera: dividi, risolvi le parti, unisci.
- Merge sort: sempre circa n log₂ n confronti, richiede memoria aggiuntiva, stabile.
- Quicksort: partizione attorno a un pivot; veloce in media, circa n²/2 con pivot sbagliati.
- Un milione di valori: circa 20 milioni di confronti invece di 500 miliardi.
- Nessun ordinamento per confronti può battere circa n log₂ n nel caso peggiore.
Fonti di questo corso (11)
- MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
- lecture notes 1 Introduction, 3 Sorting, 9 Breadth-First Search, 10 Depth-First Search (ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes) and Fall 2011 lecture 13 BFS notes (ocw.mit.edu/courses/6-006-introduction-to-algorithms-fall-2011)
- Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (MIT Press)
- with the CLRS-based Khan Academy algorithms unit by Thomas Cormen and Devin Balkcom of Dartmouth (khanacademy.org/computing/computer-science/algorithms: binary search, selection sort analysis, merge sort, quicksort overview and analysis)
- MacTutor History of Mathematics, Al-Khwarizmi (mathshistory.st-andrews.ac.uk/Biographies/Al-Khwarizmi: word algorithm from the Latin title Algoritmi de numero Indorum)
- D. E. Joyce, Euclid's Elements Book VII Propositions 1 and 2 (mathcs.clarku.edu/~djoyce/elements/bookVII)
- Wolfram MathWorld, Merge Sort (mathworld.wolfram.com/MergeSort.html: proposed by John von Neumann in 1945, after Knuth 1998 p. 159)
- Stanford CS "Tony Hoare: Quicksort" (cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/tony-hoare/quicksort.html: devised while a student at Moscow State University for Russian-English machine translation with a tape dictionary, programmed in Algol 60 and published 1961; the year 1959 from the Wikipedia Quicksort article and its cited sources)
- Bodleian Libraries, Ada Lovelace (blogs.bodleian.ox.ac.uk/adalovelace: 1843 paper, Note G Bernoulli numbers)
- Fourmilab text of Menabrea's Sketch with Lovelace's notes (fourmilab.ch/babbage/sketch.html)
- Seven Bridges of Konigsberg (Euler 1736) and Tower of Hanoi (Edouard Lucas, 1883) checked against the Wikipedia articles and their cited sources.
Consultato il: 2026-10-17