Perché mergesort O (log n)?


27

Mergesort è un algoritmo di divisione e conquista ed è O (log n) perché l'input viene dimezzato ripetutamente. Ma non dovrebbe essere O (n) perché anche se l'input è dimezzato in ciascun loop, ogni elemento di input deve essere iterato per eseguire lo scambio in ciascun array dimezzato? Questo è essenzialmente asintoticamente O (n) nella mia mente. Se possibile, fornire esempi e spiegare come contare correttamente le operazioni! Non ho ancora codificato nulla, ma ho esaminato gli algoritmi online. Ho anche allegato un gif di ciò che Wikipedia sta usando per mostrare visivamente come funziona Mergesort.

inserisci qui la descrizione dell'immagine


34
È O (n log n)
Esben Skov Pedersen,

19
Anche l'algoritmo di ordinamento di god (un ipotetico algoritmo di ordinamento che ha accesso a un oracolo che gli dice dove appartiene ogni elemento) ha un tempo di esecuzione di O (n) perché deve spostare ogni elemento che si trova in una posizione sbagliata almeno una volta.
Philipp,

Risposte:


59

È O (n * log (n)), non O (log (n)). Come hai accuratamente ipotizzato, l'intero input deve essere ripetuto, e questo deve avvenire O (log (n)) volte (l'input può essere dimezzato solo O (log (n)) volte). n voci ripetute log (n) volte danno O (n log (n)).

È stato dimostrato che nessun tipo di confronto può operare più velocemente di così. Solo i tipi che si basano su una proprietà speciale dell'input come l'ordinamento radix possono superare questa complessità. I fattori costanti di mergesort non sono in genere così grandi, quindi spesso gli algoritmi con complessità peggiore possono richiedere meno tempo.


3
s / più veloce / con complessità inferiore /
jk.

34

La complessità di merge sort è O (nlogn) e NOT O (logn).

Unisci ordinamento è un algoritmo di divisione e conquista. Pensaci in termini di 3 passaggi:

  1. Il passaggio di divisione calcola il punto medio di ciascuno dei sotto-array. Ognuno di questi passaggi richiede solo O (1) tempo.
  2. Il passaggio di conquista ordina in modo ricorsivo due sottopareti di n / 2 (anche per n) elementi ciascuno.
  3. Il passaggio di unione unisce n elementi che impiegano O (n) tempo.

Ora, per i passaggi 1 e 3, ovvero tra O (1) e O (n), O (n) è maggiore. Consideriamo i passaggi 1 e 3 che impiegano il tempo O (n) in totale. Dire che è cn per qualche costante c.

Quante volte vengono eseguiti questi passaggi?

Per questo, guarda l'albero sotto - per ogni livello dall'alto verso il basso Il livello 2 chiama il metodo di unione su 2 sotto-array di lunghezza n / 2 ciascuno. La complessità qui è 2 * (cn / 2) = cn Il livello 3 chiama il metodo di unione su 4 sotto-array di lunghezza n / 4 ciascuno. La complessità qui è 4 * (cn / 4) = cn e così via ...

Ora, l'altezza di questo albero è (logn + 1) per un dato n. Quindi la complessità complessiva è (logn + 1) * (cn). Questo è O (nlogn) per l'algoritmo di ordinamento di tipo merge.

Unisci ordinamento per n elementi

Crediti immagine: Khan Academy


9

Unisci ordinamento è un algoritmo ricorsivo e la complessità temporale può essere espressa come seguente relazione di ricorrenza.

T (n) = 2T (n / 2) + ɵ (n)

La ricorrenza sopra può essere risolta utilizzando il metodo Albero delle ricorrenze o il metodo Master. Cade nel caso II del Metodo Master e la soluzione della ricorrenza è ɵ (n log n).

La complessità temporale di Merge Sort è ɵ (nLogn) in tutti e 3 i casi (peggiore, medio e migliore) in quanto il tipo di unione divide sempre l'array in due metà e impiega un tempo lineare per unire due metà.

Divide la matrice di input in due metà, si chiama per le due metà e quindi unisce le due metà ordinate. La funzione merg () viene utilizzata per unire due metà. L'unione (arr, l, m, r) è un processo chiave che presuppone che arr [l..m] e arr [m + 1..r] siano ordinati e unisca i due sotto-array ordinati in uno. Vedere la seguente implementazione C per i dettagli.

MergeSort(arr[], l,  r)
If r > l
     1. Find the middle point to divide the array into two halves:  
             middle m = (l+r)/2
     2. Call mergeSort for first half:   
             Call mergeSort(arr, l, m)
     3. Call mergeSort for second half:
             Call mergeSort(arr, m+1, r)
     4. Merge the two halves sorted in step 2 and 3:
             Call merge(arr, l, m, r)

inserisci qui la descrizione dell'immagine

Se osserviamo più da vicino il diagramma, possiamo vedere che l'array è diviso in modo ricorsivo in due metà fino a quando la dimensione diventa 1. Una volta che la dimensione diventa 1, i processi di unione entrano in azione e iniziano a fondere nuovamente le matrici fino a quando l'array completo non è fuse.


1
Potresti approfondire la natura della parte di fusione di esso e come contribuisce alla prestazione O (n log n)?

La complessità della funzione di unione è O (n), in quanto richiede 2 array come input, confrontali e restituisci output in nuovi. Poiché sta confrontando ogni elemento con ogni altro elemento dell'array, la complessità di questa funzione di unione risulta essere O (n).
Nishant sethi,

1
Adoro questa visualizzazione del genere!
spaaarky21

0

Gli algoritmi di ordinamento basati sul confronto hanno un limite inferiore 𝞨(n*log(n)), il che significa che non è possibile avere un algoritmo di ordinamento basato sul confronto con O(log(n))complessità temporale.

A proposito, unisci ordinamento è O(n*log(n)). La pensi così.

[ a1,a2,         a3,a4,         a5,a6,          a7,a8     .... an-3,an-2,     an-1, an ] 
   \ /            \  /           \ /             \  /            \  /            \  /    
    a1'            a3'            a5'             a7'            an-3'           an-1'    
      \            /                \             /                 \             /
            a1''                          a5''                       an-3''
             \                             /                         /
                          a1'''                                     /
                           \
                                              a1''''

Questo sembra un albero binario invertito.

Lascia che sia la dimensione di input n.

Ciascuno a_nrappresenta un elenco di elementi. La prima riga a_nha solo un elemento.

Ad ogni livello, la somma del costo di fusione è in media n(esistono casi angolari il cui costo è inferiore [1]). E l'altezza dell'albero è log_2(n).

Quindi, la complessità temporale dell'ordinamento di tipo merge è O(n*log_2(n)).

[1] se l'ordinamento su un elenco che è già ordinato, che è chiamato il caso migliore. il costo ridotto a n/2 + n/4 + n/8 + .... + 1 = 2^log_2(n) -1 ~ O(n). (supponiamo che la lunghezza nsia potenza di due)


-2

L'ordinamento è un problema NP-completo in informatica (problema non polinomiale). Ciò significa che, se non dimostrato matematicamente, non è possibile scendere sotto O (n log n) quando si ordina un elenco di elementi.

Consulta questo articolo su Wikipedia ( https://en.wikipedia.org/wiki/P_versus_NP_problem )

Fondamentalmente finora nessuno è riuscito a dimostrare che (P == NP) e se lo fai, diventi prima milionario, in secondo luogo inizi la terza guerra mondiale a causa del fatto che sarai in grado di rompere tutti i meccanismi di sicurezza della chiave pub / privata utilizzati ovunque oggigiorno :)


2
Non è questo il significato di NP. Anche BubbleSort è in P. Devi fare di tutto per fare una specie che non sia in P (es. BogoSort)
Caleth,
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.