edubun
Italiano

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.

Caricamento

Trascina per ruotare. Scorri o avvicina le dita per lo zoom.

Il merge sort evidenzia la parte che si sta fondendo; il quicksort segna il pivot in viola. Porta il numero di valori a 40 e confronta i contatori con l'insertion sort.

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.

ContestoEntrambi i metodi hanno un'origine nota. Il merge sort fu proposto da John von Neumann nel 1945, quando si stavano progettando i primi computer a programma memorizzato. Il quicksort nacque da Tony Hoare, uno studente britannico all'Università statale di Mosca, nel 1959. Gli era stato offerto un lavoro sulla traduzione automatica dal russo all'inglese e, poiché il dizionario era registrato su nastro magnetico, le parole di ogni frase dovevano prima essere messe in ordine alfabetico. La sua prima idea richiedeva un tempo proporzionale al quadrato della lunghezza della frase; la seconda divenne il quicksort. Lo pubblicò nel 1961.
MetodoConfrontiMemoria aggiuntiva
Insertion sortdi solito circa n²/4, nel caso peggiore circa n²/2nessuna; stabile
Merge sortcirca n log₂ n, sempreuna seconda lista di n valori; stabile
Quicksortdi solito circa n log₂ n, nel caso peggiore circa n²/2 (pivot sbagliati)poca; le versioni usuali non sono stabili
Un ordinamento per confronti può battere n log₂ n? No. Un ordinamento che impara solo confrontando coppie deve saper distinguere tutti gli n! possibili ordini di partenza, e ogni confronto ha due esiti, quindi il caso peggiore richiede almeno log₂(n!) confronti, che crescono come n log₂ n. Per 10 valori questo limite è di 22 confronti.
divide et imperaDividere 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 sortDimezza, ordina ogni metà, fondi: circa n log₂ n confronti
pivotIl valore attorno a cui il quicksort divide la lista
partizioneRisistemare la lista in modo che i valori più piccoli stiano prima del pivot e gli altri dopo
quicksortPartiziona attorno a un pivot, poi ordina ciascuna parte
ordinamento stabileI valori uguali mantengono il loro ordine originale
sul posto (in place)Ordina dentro la lista originale con poca memoria aggiuntiva
  1. Quanti confronti servono per fondere [1, 4, 7] e [2, 3, 8]?
  2. Quanti confronti servono per fondere [1, 2, 3] e [4, 5, 6]?
  3. Una lista di 16 valori viene dimezzata finché ogni parte ha un solo valore. Quanti livelli di dimezzamento ci sono?
  4. 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
  5. 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
  6. Il quicksort con l'ultimo valore come pivot viene eseguito sulla lista già ordinata [1, 2, 3, 4, 5]. Quanti confronti fa?
  7. Quale metodo ha bisogno di una seconda lista grande quanto l'input?
    • Merge sort
    • Quicksort
    • Insertion sort
  8. Chi propose il merge sort nel 1945?
    • Tony Hoare
    • John von Neumann
    • Ada Lovelace
    • Euclide
  9. 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
  10. 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
  11. Qual è il minimo numero di confronti nel caso peggiore per un qualsiasi ordinamento per confronti di 10 valori (log₂ 10!, arrotondato per eccesso)?
Punti chiave
  • 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