Perché la ricerca binaria è più veloce della ricerca ternaria?


49

Cercando un array di elementi utilizzando ricerca binaria prende, nel peggiore dei casi di log 2 N iterazioni perché, ad ogni passo ci rifila la metà del nostro spazio di ricerca. Se invece avessimo usato la "ricerca ternaria", avremmo tagliato i due terzi del nostro spazio di ricerca ad ogni iterazione, quindi il caso peggiore dovrebbe prendere log 3 N < log 2 N iterazioni ...Nlog2Nlog3N<log2N

Sembra che la ricerca ternaria sia più veloce, quindi perché utilizziamo la ricerca binaria?


3
Non si potrebbe usare lo stesso ragionamento sulla ricerca quaternaria? O anche la ricerca decimale ... o qualcosa di più grande di 2.
d'alar'cop

4
per favore leggi di B + Trees
arunmoezhi l'

5
La ricerca lineare spesso è più veloce della ricerca binaria su problemi di piccole e medie dimensioni su hardware moderno, perché è coerente con la cache e quasi tutti i rami sono previsti correttamente.
Pseudonimo,

2
Anche 2 * log_3 (N) = log_3 (N ^ 2) se parla al tuo intuito.
PawelP

6
Mettiamolo in termini intuitivi. Se l'utilizzo di una ricerca basata su 3 è più veloce perché riduce lo spazio di ricerca ad ogni iterazione, allora non sta usando una ricerca basata su milioni più veloce? Ma puoi facilmente vedere che in media dovresti fare 500.000 controlli all'interno di ogni iterazione per determinare la milionesima porzione che conteneva il target. Chiaramente, tagliando lo spazio di ricerca a metà di ogni iterazione e non di più, si ottiene la maggior parte delle informazioni in un unico passaggio, in modo affidabile.
ErikE,

Risposte:


76

log2(n)+O(1)
2log3(n)+O(1)
2log3(n)+O(1)=2log(2)log(3)log2(n)+O(1)
2log(2)log(3)>1

n

nf(k)=(k1)log(2)log(k)k


1
E LHS è lineare e RHS è logaritmico, quindi non aiuterà per nessun quaternario o qualcosa di più .... Belle spiegazioni .... Grazie
The Mean Square

3
Solo per completezza: si noti che una misura astratta come il numero di confronti tra elementi può o meno dominare il tempo di esecuzione effettivo. In particolare, potrebbe essere necessario considerare quanti errori di cache è probabile che si verifichino su array lunghi con entrambe le ricerche. (Qui coincidono. Sto solo notando questo perché l'OP chiede "perché è più veloce?", E rispondendo che con una misura astratta può essere fuorviante per alcuni algoritmi.)
Raphael

10
In una ricerca ternaria, 1/3 del tempo avrai bisogno solo di 1 confronto (fai un confronto più basso: se nel terzo inferiore, non hai bisogno del secondo confronto). Ciò rende solo il 5% più lento del ternario invece del 25% (in questo mondo in cui ci interessa solo il conteggio dei confronti). Non sono sicuro di come generalizzare questo su n-ary, anche se sospetto che non sia mai più veloce del binario.
Aaron Dufour,

2
@AaronDufour: Dal momento che si potrebbe fare una ricerca quaternaria confrontando prima l'elemento centrale e quindi ignorando il risultato degli altri confronti, l'unico modo in cui la ricerca quaternaria potrebbe essere più veloce sarebbe se tre confronti potessero essere fatti in parallelo più a buon mercato di due confronti potrebbe essere eseguito in sequenza.
Supercat

1
@AaronDufour Ma stai ammortizzando gli elementi da cercare, e non mi è chiaro perché sia ​​ok. Nel peggiore dei casi, entrambi i confronti possono essere eseguiti in ogni fase.
Sasho Nikolov,

26

DCTLib ha ragione, ma dimentica la matematica per un secondo.

Quindi, secondo la tua logica, n -ary dovrebbe essere il più veloce. Ma se ci pensate, n -ary è esattamente uguale a una normale ricerca di iterazioni (iterando semplicemente la lista 1 per 1, ma in ordine inverso). Innanzitutto seleziona l'ultimo (o il prossimo all'ultimo) elemento nell'elenco e confronta quel valore con il tuo valore di confronto. Quindi rimuovi quell'elemento dal tuo elenco e quindi scegli l'ultimo elemento nel nuovo elenco, che è solo l'ultimo all'ultimo valore dell'array. Ogni volta, elimineresti solo 1 valore alla volta fino a quando non avrai trovato il tuo valore.

Invece, dovresti pensarci in questo modo - come posso eliminare la maggior parte dei valori dall'elenco ogni iterazione? In una ricerca binaria, elimini sempre metà dell'elenco. In una ricerca ternaria, esiste la possibilità (33,33% di probabilità, in realtà) che è possibile eliminare i 2/3 dell'elenco, ma esiste una possibilità ancora maggiore (66,66%) di eliminare solo 1/3 dell'elenco. per calcolare O (n), devi guardare lo scenario peggiore, che è 1/3, meno di 1/2. Man mano che ti avvicini sempre di più a n, diventa anche peggio.

Non solo lo scenario peggiore sarà migliorato con la ricerca binaria, ma migliorerà anche il tempo medio . Guardando il valore atteso (quale parte dell'elenco possiamo rimuovere in media), utilizziamo questa formula:

(P_lower) x (porzione che possiamo rimuovere se inferiore) + (P_higher) x (porzione che possiamo rimuovere se superiore) = E

Per la ricerca binaria, questo è .5x.5 + .5x.5 = .5 (rimuoviamo sempre metà dell'elenco). Per le ricerche ternarie, questo valore è .666x.333 + .333x.666 = 0.44, o ad ogni passo, probabilmente rimuoveremo solo il 44% dell'elenco, rendendolo in media meno efficiente della ricerca binaria. Questo valore raggiunge un picco di 1/2 (metà dell'elenco) e diminuisce con l'avvicinarsi di n (iterazione inversa) e 0 (iterazione regolare).

Ok, quindi ho mentito ... c'è un po 'di matematica in gioco, ma spero che ti aiuti!


1
Questa è un'ottima risposta
The_Sympathizer il

L'analisi dei confini aiuta a capire la matematica difficile! La ricerca sequenziale n-ary ha lo stesso costo della ricerca lineare O (n).
shuva,

-2

Si noti che l'argomento di confronto log (N) vs 2 log (N) si basa su un'interpretazione ingenua dell'algoritmo. Se dovessi davvero sedermi e scrivere questo in assembly x86 i risultati sarebbero invertiti. Il problema è l'uso di numeri interi per casi di test combinati con un compilatore non sufficientemente intelligente che non è in grado di rimuovere i confronti ridondanti. Riprova con le stringhe e un'apposita funzione di confronto delle stringhe e codificala per chiamare la funzione di confronto una volta per ciclo e troverai che la ricerca ternaria è di nuovo più veloce.


2
Naturalmente la ricerca ternaria sarebbe più veloce se potessi farlo con un solo confronto per iterazione. Ma, non importa se stringhe o numeri interi, non puoi.
FrankW,

I confronti non sarebbero ridondanti e il problema non ha nulla a che fare con il compilatore. Per dividere lo spazio di ricerca in tre parti, sono necessari 2 confronti. In una ricerca binaria, devi solo confrontare con l'elemento centrale e poi sai in quale metà dello spazio di ricerca si troverebbe il risultato. Con la ricerca ternaria, dovresti confrontare con l'elemento 1/3 del percorso attraverso il elenco E quello 2/3 del percorso attraverso l'elenco. Che tipo di dati stai confrontando o che lingua stai usando è irrilevante. Concesso, se l'articolo è nel 1 ° 3 °, potresti fermarti dopo 1 confronto.
reirab

2
Su alcune piattaforme, la ricerca ternaria potrebbe essere più veloce perché consente alla CPU più tempo per recuperare gli operandi dalla RAM prima di averne bisogno per il confronto. Ma ciò dipende totalmente dalla piattaforma utilizzata e dalle sue latenze e cache.
jpa,

1
Accidenti, definizione errata della ricerca ternaria.
Giosuè,
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.