Quali sono le caratteristiche di a


19

A volte è facile identificare la complessità temporale di un algoritmo che sto esaminando attentamente. Gli algoritmi con due loop nidificati di sono ovviamente . Gli algoritmi che esplorano tutte le possibili combinazioni di gruppi di due valori sono ovviamenteN 2 N 2 NNN2N2N .

Tuttavia non so come "individuare" un algoritmo con complessità . Un'implementazione ricorsiva di mergesort, per esempio, è una. Quali sono le caratteristiche comuni di mergesort o altroΘ ( N log N )Θ(NlogN)Θ(NlogN) algoritmi che potrebbero darmi un indizio se ne analizzassi uno?

Sono sicuro che esiste più di un modo in cui un algoritmo può avere una complessità di , quindi tutte le risposte sono apprezzate. A proposito, sto cercando caratteristiche generali e suggerimenti, non prove rigorose.Θ(NlogN)


6
O(logn) significa albero.
Pratik Deoghare il


2
@PratikDeoghare: non necessariamente.
Raffaello

3
@Raphael intendevo principalmente! :)
Pratik Deoghare il

Risposte:


17

Il tuo archetipo Θ(nlogn) è un algoritmo di divisione e conquista , che divide (e ricombina) il lavoro in un tempo lineare e ricorre sui pezzi. Unisci ordinamento funziona in questo modo: impiega O(n) tempo a dividere l'input in due pezzi approssimativamente uguali, ordina ricorsivamente ogni pezzo e impiega Θ(n) tempo combinando le due metà ordinate.

Intuitivamente, continuando l'idea di dividere e conquistare, ogni fase di divisione richiede un tempo lineare in totale, perché l'aumento del numero di pezzi da dividere corrisponde esattamente alla diminuzione delle dimensioni dei pezzi, poiché il tempo impiegato dalla divisione è lineare. Il tempo di esecuzione totale è il prodotto del costo totale di una fase di divisione moltiplicato per il numero di fasi di divisione. Poiché la dimensione dei pezzi viene dimezzata ogni volta, ci sono fasi di divisione del , quindi il tempo di esecuzione totale è n registro ( n )log2(n)nlog(n) . (Fino a una costante moltiplicativa, la base del logaritmo è irrilevante.)

Mettendolo in equazioni (), un modo per stimare il tempo di esecuzione di un tale algoritmo è quello di esprimerlo in modo ricorsivo: T ( n ) = 2 T ( n / 2 ) + Θ ( n ) . È chiaro che questo algoritmo richiede più del tempo lineare e possiamo vedere molto di più dividendo per n : T ( n )T(n)T(n)=2T(n/2)+Θ(n)n Quandonraddoppia,T(n)/naumenta di una quantità costante:T(n)/naumenta logaritmicamente, o in altre parole,T(n)=Θ(nlogn)

T(n)n=T(n/2)n/2+Θ(1)
nT(n)/nT(n)/nT(n)=Θ(nlogn) .

Questa è un'istanza di un modello più generale: il teorema principale . Per qualsiasi algoritmo ricorsivo che divide il suo input di dimensione in un pezzo di dimensione n / b e impiega un tempo f ( n ) per eseguire la divisione e la ricombinazione, il tempo di esecuzione soddisfa T ( n ) = a T ( n / b ) + f ( n ) . Questo porta ad una forma chiusa che dipende dai valori di un e b e la forma dinan/bf(n)T(n)=aT(n/b)+f(n)ab . Sef e f ( n ) = Θ ( n ) , il teorema principale afferma che T ( n ) = Θ ( n log n ) .a=bf(n)=Θ(n)T(n)=Θ(nlogn)


1
Riassumendo: gli algoritmi che eliminano le frazioni costanti dello spazio di ricerca alla volta esibiranno termini logaritmici. Gli altri fattori dipendono da quanto tempo ci vuole per eseguire il fare via.
Raffaello

1
esempio: caso medio Quicksort O(nlogn)
vzn

11

Altre due categorie di algoritmi che richiedono tempo:Θ(nlogn)

Algoritmi in cui ogni elemento viene elaborato a turno e ci vuole tempo logaritmico per elaborare ciascun elemento (ad es. HeapSort o molti degli algoritmi di geometria computazionale di sweep del piano).

Algoritmi in cui il tempo di esecuzione è dominato da una fase di pre-elaborazione dell'ordinamento. (Ad esempio, nell'algoritmo di Kruskal per l'albero di spanning minimo, possiamo ordinare i bordi in base al peso come primo passo).


Eseguito l'upgrade per il primo paragrafo. Il secondo sembra ridondante, dal momento che gli algoritmi di ordinamento linearitmico che conosciamo sono o divide e conquista o heapsort. Un esempio per la prima categoria è la ricerca di oggetti in un albero di ricerca binario (o matrice ordinata) di dimensione n ; a un livello più astratto, ciò può anche essere visto come divisione e conquista. nn
Raffaello

@Raphael So che l'ordinamento è ridondante con le categorie di tempi di esecuzione già indicati. Il punto è che l'ordinamento a volte è il "collo di bottiglia" e gli algoritmi in cui a prima vista la domanda non riguarda l'ordinamento possono ancora avere il tempo di esecuzione perché è necessario l'ordinamento.
Joe,

9

Un'altra categoria: algoritmi in cui l' output ha dimensione , e quindi Θ ( n log n ) il tempo di esecuzione è lineare nella dimensione dell'output .Θ(nlogn)Θ(nlogn)

Sebbene i dettagli di tali algoritmi utilizzino spesso tecniche di divisione e conquista, non devono necessariamente. Il tempo di esecuzione deriva fondamentalmente dalla domanda posta, quindi penso che valga la pena menzionarlo separatamente.

Questo si presenta in strutture di dati che si basano su un albero di ricerca binario aumentato, in cui ciascun nodo memorizza una struttura di dati di dimensioni lineari per cercare le foglie nella sottostruttura di quel nodo. Tali strutture di dati emergono spesso nella ricerca dell'intervallo geometrico e sono spesso basate su uno schema di decomposizione . Vedi il sondaggio di Agarwal .

Per un esempio concreto, prendere in considerazione l' intervallo-albero , creato per rispondere a query di intervallo ortogonali bidimensionali. Sebbene lo spazio sia stato successivamente ridotto utilizzando alcune tecniche di compressione per impacchettare più oggetti in una sola parola, la versione del libro di testo (e la più intuitiva) della struttura dei dati richiede lo spazio (ogni foglia è memorizzata in una struttura ausiliaria in ogni nodo sul percorso dalla foglia alla radice, o in posizioni O ( log n ) ), e l'algoritmo di costruzione impiega un tempo lineare nello spazio richiesto .O(nlogn)O(logn)


Un esempio sarebbe trovare l'n-esimo numero primo usando un setaccio, perché avresti bisogno di un setaccio di dimensioni . θ(nlogn)
gnasher729,

6

Una complessità di deriva dagli algoritmi di divisione e conquista che dividono il loro input in k pezzi di dimensioni approssimativamente uguali nel tempo O ( n ) , operano su questi pezzi in modo ricorsivo e poi li combinano nel tempo O ( n ) . Se si opera solo su alcuni pezzi, il tempo di esecuzione scende a O ( n ) .O(nlogn)kO(n)O(n)O(n)


5

Si tratta in genere di algoritmi della varietà "divide and conquer", in cui il costo della divisione e della combinazione di subsolutions non è "troppo grande". Dai un'occhiata a queste FAQ per vedere quali tipi di recidive danno origine a questo comportamento.


3

Tipicamente, gli algoritmi di divisione e conquista producono complessità O (N log N).


-1

Un esempio generico di un ciclo ( non un algoritmo in sé) che viene eseguito in è il seguente:O(nlogn)

for (i = 0; i < constant; i++){
    for(j = 0; j < n; j++){
        // Do some O(1) stuff on the input
    }
}

// Alternative Variant:
for (i = 0; i < constant; i++){
    for(j = n; j < constant; j++){
        // Do some O(1) stuff on the input
    }
}

(nota che questi loop nidificati non sono O(n2) . Nota anche che non è divisione e conquista né ricorsivo.)

Non posso dare un esempio concreto di un algoritmo che utilizza questo loop, ma si presenta spesso quando si codificano algoritmi personalizzati.


O(nlogn)Θ(n)Θ(1)Θ(|n|)n

O(nlogn)

inoltre, la domanda originale non chiedeva big-theta.
Nicolas Miari,

1
Certo, ma qualsiasi algoritmo che gira in tempo lineare o costante èO(nlogn), oltre ad essere O(22n) e O(quasi tutto il resto). La tua risposta non ha nulla a che fare con i logaritmi. Se si desidera chiarire che la domanda dovrebbe essere postaΘ(nlogn) piuttosto che O(nlogn)quindi fai esplicito questo punto come commento alla domanda o, ancora meglio, modifica la domanda.
David Richerby,

Volevo sottolineare il punto in cui ho effettivamente cercato su InternetO(nlogn) per vedere se il ciclo nella mia risposta, che dovevo trovare per una risposta effettiva a un vero problema di programmazione che era necessario per eseguire O(nlogn), era in realtà O(nlogn)o no. E la maggior parte delle informazioni relative agli algoritmi di divisione e conquista, vale la pena menzionare. Non pretendo che la mia risposta sia l'archetipoO(nlogn)algoritmo.
Nicolas Miari,
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.