Qual è l'algoritmo di ordinamento più veloce per un array di numeri interi?


55

Mi sono imbattuto in molti algoritmi di smistamento durante i miei studi alle superiori. Tuttavia, non so mai quale sia il più veloce (per una matrice casuale di numeri interi). Quindi le mie domande sono:

  • Qual è l'algoritmo di ordinamento più veloce attualmente conosciuto?
  • Teoricamente, è possibile che ce ne siano anche di più veloci? Quindi, qual è la minima complessità per l'ordinamento?

7
Cosa intendi con "veloce"? Cosa vuoi misurare?
Raffaello

2
Che cosa significa "array casuale di numeri interi"? Casuale con quale distribuzione? distribuzione uniforme? Gaussiana? A seconda della distribuzione, potrebbero esserci algoritmi del tempo di esecuzione previsti rispetto a . O(nlogn)
Bakuriu,

@gen Dai un'occhiata al tipo di Radix. Ad esempio, la corretta implementazione presenta una complessità O (n) per Int32.
questo

Dai

1
@gen: in termini di asintotici? Quindi, è facile: scegli uno qualsiasi degli algoritmi Θ ( n log n ) . Nota che questo potrebbe non avere nulla a che fare con le prestazioni (medie) del mondo reale. Questo può essere una lettura utile in questo senso. ΘΘ(nlogn)
Raffaello

Risposte:


42

In termini generali, ci sono gli algoritmi di ordinamento , come ordinamento di inserzione, ordinamento a bolle e ordinamento di selezione, che in genere è necessario utilizzare solo in circostanze speciali; Quicksort, che è il caso peggiore O ( n 2 ) ma abbastanza spesso O ( n log n ) con costanti e proprietà buone e che può essere utilizzato come procedura di ordinamento per scopi generici; gli algoritmi O ( n log n ) , come merge-sort e heap-sort, che sono anche buoni algoritmi di ordinamento per scopi generici; e la O ( nO(n2)O(n2)O(nlogn)O(nlogn)O(n)o algoritmi di ordinamento lineari per elenchi di numeri interi, come radix, bucket e ordinamenti di conteggio, che possono essere adatti a seconda della natura dei numeri interi nei propri elenchi.

Se gli elementi nel tuo elenco sono tali che tutto ciò che sai su di essi è la relazione totale dell'ordine tra loro, gli algoritmi di ordinamento ottimali avranno complessità Ω(nlogn) . Questo è un risultato abbastanza interessante e per il quale dovresti essere in grado di trovare facilmente i dettagli online. Gli algoritmi di ordinamento lineare sfruttano ulteriori informazioni sulla struttura degli elementi da ordinare, piuttosto che solo la relazione di ordine totale tra gli elementi.

Ancor più in generale, l'ottimalità di un algoritmo di ordinamento dipende intimamente dalle ipotesi che è possibile fare riguardo al tipo di elenchi che si intende ordinare (nonché dal modello di macchina su cui verrà eseguito l'algoritmo, che può rendere anche ordinamento altrimenti scarso algoritmi la scelta migliore; considerare l'ordinamento a bolle su macchine con un nastro per l'archiviazione). Più forti sono i tuoi presupposti, più angoli il tuo algoritmo può tagliare. In base a ipotesi molto deboli su quanto sia possibile determinare in modo efficiente "ordinamento" di un elenco, la complessità ottimale nel caso peggiore può persino essere Ω(n!) .

Questa risposta riguarda solo le complessità. I tempi di esecuzione effettivi delle implementazioni degli algoritmi dipenderanno da un gran numero di fattori che sono difficili da spiegare in una singola risposta.


Immagino che alcune di quelle dovrebbero essere Ω ? OΩ
Raffaello

1
@Raphael Meh. Penso che la maggior parte di loro sia comunque. Suppongo che il limite inferiore sia probabilmente reso meglio Ω . Ne cambierò un paio che hanno più senso. ΘΩ
Patrick87,

7
Io voto @Raphael ottiene un cappello di polizia : PΩ
Realz Slaw

2
@RealzSlaw: lo indosserei con orgoglio. :]
Raffaello

1
@gen Vedere stackoverflow.com/a/3274203~~V~~singular~~3rd per qualche discussione. Fondamentalmente, se i singoli record sono enormi e non sono archiviati in modo casuale e la quantità di dati è tale che deve essere eseguita sul posto, allora l'ordinamento delle bolle è la strada da percorrere. Al giorno d'oggi queste circostanze sono generalmente rare, ma potresti ancora incontrarle.
Patrick87,

16

La risposta, come spesso accade per tali domande, è "dipende". Dipende da cose come (a) quanto sono grandi gli interi, (b) se l'array di input contiene numeri interi in un ordine casuale o in un ordine quasi ordinato, (c) se è necessario che l'algoritmo di ordinamento sia stabile o no, così come altri fattori, (d) se l'intero elenco di numeri si adatta alla memoria (ordinamento in memoria vs ordinamento esterno) e (e) la macchina su cui lo si esegue.

In pratica, l'algoritmo di ordinamento nella libreria standard della tua lingua sarà probabilmente abbastanza buono (abbastanza vicino all'ottimale), se hai bisogno di un ordinamento in memoria. Pertanto, in pratica, basta usare qualsiasi funzione di ordinamento fornita dalla libreria standard e misurare il tempo di esecuzione. Solo se scopri che (i) l'ordinamento è una grande frazione del tempo di esecuzione complessivo e (ii) il tempo di esecuzione è inaccettabile, dovresti preoccuparti di smanettare con l'algoritmo di ordinamento. Se queste due condizioni lo fanno presa, allora si può guardare gli aspetti specifici del vostro settore particolare e sperimentare con altri algoritmi di ordinamento veloce.

Ma realisticamente, in pratica, l'algoritmo di ordinamento è raramente un grosso collo di bottiglia nelle prestazioni.


9

Inoltre, rispondendo alla tua seconda domanda

Teoricamente, è possibile che ce ne siano anche di più veloci?
Quindi, qual è la minima complessità per l'ordinamento?

Per l'ordinamento per scopi generici, la complessità del problema di ordinamento basato sul confronto è Ω (n log n) . Esistono alcuni algoritmi che eseguono l'ordinamento in O (n), ma tutti si basano su ipotesi sull'input e non sono algoritmi di ordinamento per scopi generali.

Fondamentalmente, la complessità è data dal numero minimo di confronti necessari per l'ordinamento dell'array (log n rappresenta l'altezza massima di un albero decisionale binario creato durante il confronto di ciascun elemento dell'array).

È possibile trovare la prova formale per la complessità di ordinamento più bassa qui :


3
Ω(nlogn)

Dipende da cosa intendi per problema di ordinamento . I tipi basati sul confronto per scopi generici non sono l'unico tipo di problemi di ordinamento che le persone hanno.
Patrick87,

1
È vero, certo. Avrei dovuto essere più specifico, grazie per averlo sottolineato. Tuttavia, ero un po 'curioso su quali altri approcci di ordinamento (non basati sul confronto) a cui ti riferivi; Radix Sort è esattamente il tipo di algoritmo O (n) di cui stavo parlando - devi "assumere" qualcosa sull'input (numeri interi a larghezza fissa). In questo senso, non è un algoritmo di ordinamento generico, giusto?
rla4,

1
@DW: l'ordinamento Radix non deve essere considerato un algoritmo di ordinamento "per scopi generici", poiché richiede chiavi intere di lunghezza fissa; non è utile altrimenti. Ma ho capito il tuo punto. :) Immagino che il mio errore si sia concentrato sull'ordinamento di qualsiasi cosa che potesse essere confrontata, anziché sull'ordinamento di numeri interi , in particolare. Sono problemi diversi e hanno una serie diversa di possibili soluzioni. La domanda menziona "un array casuale di numeri interi", ma ammetto di averlo preso come esempio, piuttosto che come una restrizione.
rla4,

2
@DavidRicherby, ripensandoci dopo un anno e mezzo, sono d'accordo con te. Grazie.
DW

3

O(nloglogn)O(nlogn)


2
nlognΩ(nlogn)O(nloglogn)
David Richerby,

1

Ho letto le altre due risposte al momento della stesura di questo e non pensavo che nessuno dei due avesse risposto alla tua domanda in modo appropriato. Altre risposte hanno preso in considerazione idee estranee sulle distribuzioni casuali e sulla complessità dello spazio che probabilmente non rientrano negli studi delle scuole superiori. Quindi ecco la mia opinione.

An(n1)A(n1)Ω(n)O(n)Ω(n)

Ω(n)O(n)n2n3n51n2


O(n)nlgnn232O(n)O(nlgn)(per quicksort o mergesort), in pratica il confronto non è del tutto chiaro: le costanti nascoste nella notazione big-O diventano molto importanti e la costante per l'ordinamento radix è superiore alla costante per quicksort o mergesort.
DW

lg(n)n

Ω(n)

2
O(wn)www{0,,2w1}lognnw=lognnlogn.
David Richerby,

1

O(nloglogn)
O(nloglogU)U


0

Dato che non menzioni alcuna restrizione sull'hardware e dato che stai cercando "il più veloce", direi che dovresti scegliere uno degli algoritmi di ordinamento parallelo basati sull'hardware disponibile e sul tipo di input che hai.

In teoria esempio quick_sortè O(n log n). Con i pprocessori, idealmente questo dovrebbe ridursi O(n/p log n)se lo eseguiamo in parallelo.

Per citare Wikipedia: complessità temporale di ...

L'ordinamento parallelo ottimale è O (log n)

In pratica, per enormi dimensioni di input sarebbe impossibile ottenere a O(log n)causa di problemi di scalabilità.

Ecco lo pseudo codice per l' ordinamento di tipo Parallel merge . L'implementazione di merge()può essere la stessa dell'ordinamento di tipo merge:

// Sort elements lo through hi (exclusive) of array A.
algorithm mergesort(A, lo, hi) is
    if lo+1 < hi then  // Two or more elements.
        mid = ⌊(lo + hi) / 2⌋
        fork mergesort(A, lo, mid)
        mergesort(A, mid, hi)
        join
        merge(A, lo, mid, hi)

Vedi anche:


O(n2)

@Evil Sì. Quicksort non è adatto per l'elaborazione parallela. È un esempio Quelli che dovrebbero essere usati sono elencati nei link forniti.
Kashyap,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.