Come Merge Sort, QuickSort è un algoritmo di divisione e conquista. Sceglie un elemento come pivot e partiziona larray dato attorno al pivot selezionato. Esistono molte versioni differenti di quickSort che selezionano il pivot in modi diversi.
- Scegli sempre il primo elemento come pivot.
- Scegli sempre lultimo elemento come pivot (implementato di seguito)
- Scegli un elemento casuale come pivot.
- Scegli mediana come pivot.
Il processo chiave in quickSort è partition (). Lobiettivo delle partizioni è, dato un array e un elemento x dellarray come pivot, inserire x nella sua posizione corretta nellarray ordinato e inserire tutti gli elementi più piccoli (minori di x) prima di x, e inserire tutti gli elementi maggiori (maggiori di x) dopo X. Tutto questo dovrebbe essere fatto in tempo lineare.
Pseudo codice per la funzione QuickSort ricorsiva:
Algoritmo di partizione
Ci possono essere molti modi per fare la partizione, seguendo lo pseudo codice adotta il metodo fornito nel libro CLRS. La logica è semplice, partiamo dallelemento più a sinistra e teniamo traccia dellindice degli elementi più piccoli (o uguali a) come i. Durante lattraversamento, se troviamo un elemento più piccolo, scambiamo lelemento corrente con arr. Altrimenti ignoriamo lelemento corrente.
Pseudo codice per partition ()
Illustrazione di partition ():
Implementazione:
Di seguito sono riportate le implementazioni di QuickSort:
Risultato:
Sorted array:1 5 7 8 9 10
Analisi di QuickSort
Il tempo impiegato da QuickSort in generale può essere scritto come segue.
T(n) = T(k) + T(n-k-1) + (n)
I primi due termini sono per due chiamate ricorsive, lultimo termine è per il processo di partizione. k è il numero di elementi più piccoli del pivot.
Il tempo impiegato da QuickSort dipende dalla matrice di input e dalla strategia di partizione. Di seguito sono riportati tre casi.
Caso peggiore: il caso peggiore si verifica quando il processo di partizione sceglie sempre lelemento più grande o più piccolo come pivot. Se consideriamo la strategia di partizione sopra in cui lultimo elemento è sempre scelto come pivot, il caso peggiore si verificherebbe quando larray è già ordinato in ordine crescente o decrescente. Di seguito è riportata la ricorrenza nel caso peggiore.
T(n) = T(0) + T(n-1) + (n)which is equivalent to T(n) = T(n-1) + (n)
La soluzione della ricorrenza di cui sopra è (n2).
Caso migliore: il caso migliore si verifica quando il processo di partizione sceglie sempre il elemento centrale come perno. Di seguito è riportata la ricorrenza nel migliore dei casi.
T(n) = 2T(n/2) + (n)
La soluzione della ricorrenza di cui sopra è (nLogn). Può essere risolto usando il caso 2 del Teorema Master.
Caso medio:
Per fare unanalisi del caso medio, dobbiamo considerare tutte le possibili permutazioni di array e calcolare il tempo impiegato da ogni permutazione che non sembra facile.
Possiamo avere unidea del caso medio considerando il caso in cui la partizione inserisce O (n / 9) elementi in un insieme e O (9n / 10) elementi in un altro insieme. Di seguito è riportata la ricorrenza per questo caso.
T(n) = T(n/9) + T(9n/10) + (n)
Anche la soluzione della ricorrenza di cui sopra è O (nLogn)
Sebbene la complessità temporale del caso peggiore di QuickSort sia O (n2) che è più di molti altri algoritmi di ordinamento come Merge Sort e Heap Sort, QuickSort è più veloce nella pratica, perché il suo ciclo interno può essere implementato in modo efficiente sulla maggior parte delle architetture e nella maggior parte dei dati del mondo reale. QuickSort può essere implementato in diversi modi modificando la scelta del pivot, in modo che il caso peggiore si verifichi raramente per un dato tipo di dati. Tuttavia, lordinamento di tipo merge è generalmente considerato migliore quando i dati sono enormi e archiviati in una memoria esterna.
QuickSort è stabile?
Limplementazione predefinita non è stabile. Tuttavia, qualsiasi algoritmo di ordinamento può essere reso stabile considerando gli indici come parametro di confronto.
QuickSort è attivo?
Secondo lampia definizione di algoritmo sul posto, si qualifica come algoritmo di ordinamento sul posto poiché utilizza spazio solo per memorizzare chiamate di funzioni ricorsive ma non per manipolare linput.
Come implementare QuickSort per elenchi collegati?
QuickSort su elenchi collegati singolarmente
QuickSort su elenco a doppio collegamento
Possiamo implementare QuickSort in modo iterativo?
Sì, fare riferimento a QuickSort iterativo.
Perché Quick Sort è preferito a MergeSort per lordinamento di array
Lordinamento rapido nella sua forma generale è un ordinamento sul posto (cioè non richiede alcuno spazio di archiviazione aggiuntivo) mentre lordinamento di unione richiede O (N) spazio di archiviazione extra, N che denota la dimensione dellarray che può essere piuttosto costoso. Lallocazione e la de-allocazione dello spazio aggiuntivo utilizzato per lordinamento di unione aumenta il tempo di esecuzione dellalgoritmo. Confrontando la complessità media troviamo che entrambi i tipi di tipi hanno complessità media O (NlogN) ma le costanti differiscono. Per gli array, lunione dellordinamento perde a causa delluso di spazio di archiviazione O (N) aggiuntivo.
La maggior parte delle implementazioni pratiche di Ordinamento rapido utilizzano la versione casuale. La versione randomizzata ha previsto una complessità temporale di O (nLogn).Il caso peggiore è possibile anche nella versione randomizzata, ma il caso peggiore non si verifica per un modello particolare (come un array ordinato) e lordinamento rapido casuale funziona bene nella pratica.
Lordinamento rapido è anche un ordinamento adatto alla cache algoritmo in quanto ha una buona località di riferimento quando viene utilizzato per gli array.
Lordinamento rapido è anche ricorsivo di coda, quindi viene eseguita lottimizzazione delle chiamate di coda.
Perché MergeSort è preferito a QuickSort per gli elenchi collegati ?
In caso di elenchi concatenati, il caso è diverso principalmente a causa della differenza nellallocazione di memoria di array ed elenchi concatenati. A differenza degli array, i nodi dellelenco collegato potrebbero non essere adiacenti in memoria. A differenza dellarray, nellelenco collegato, possiamo inserire elementi nel mezzo nello spazio extra O (1) e nel tempo O (1). Pertanto loperazione di unione dellordinamento di unione può essere implementata senza spazio aggiuntivo per gli elenchi concatenati.
Negli array, possiamo eseguire laccesso casuale poiché gli elementi sono continui in memoria. Supponiamo di avere un array A intero (4 byte) e che lindirizzo di A sia x, quindi per accedere ad A, possiamo accedere direttamente alla memoria in (x + i * 4). A differenza degli array, non possiamo eseguire laccesso casuale nellelenco collegato. Lordinamento rapido richiede molto di questo tipo di accesso. Nellelenco collegato per accedere allith index, dobbiamo viaggiare su ogni singolo nodo dalla testa allith nodo poiché non abbiamo un blocco continuo di memoria. Pertanto, loverhead aumenta per lordinamento rapido. Lordinamento di tipo merge accede ai dati in modo sequenziale e la necessità di accesso casuale è bassa.
Come ottimizzare QuickSort in modo che occupi O (Log n) spazio extra nel peggiore dei casi?
Vedere QuickSort Tail Call Optimization (Reducing worst case space to Log n)
Istantanee:
- Quiz su QuickSort
- Articoli recenti su QuickSort
- Pratica di codifica per ordinamento.
Altri algoritmi di ordinamento su GeeksforGeeks / GeeksQuiz:
Sort Sort, Bubble Sort, Insertion Sort, Merge Sort, Heap Sort, QuickSort , Radix Sort, Counting Sort, Bucket Sort, ShellSort, Comb Sort, Pigeonhole Sort