Qual è il tempo O nel determinare se un valore si trova in un array ordinato?
-
19-08-2019 - |
Domanda
Ho un array ordinato di 5000 numeri interi. Quanto velocemente posso dire se un numero intero casuale è un membro dell'array? Una risposta in generale, C e Ruby sarebbero carini.
I valori dell'array sono nella forma
c * c + 1
dove c
può essere qualsiasi numero intero compreso tra 1 e 5000.
Ad esempio:
[2, 5, 10, 17, 26, 37, 50 ...]
Soluzione
La ricerca binaria, come altri hanno già detto, è O (log2N) e può essere codificata in modo ricorsivo:
BinarySearch(A[0..N-1], value, low, high) {
if (high < low)
return -1 // not found
mid = (low + high) / 2
if (A[mid] > value)
return BinarySearch(A, value, low, mid-1)
else if (A[mid] < value)
return BinarySearch(A, value, mid+1, high)
else
return mid // found
}
o iterativamente:
BinarySearch(A[0..N-1], value) {
low = 0
high = N - 1
while (low <= high) {
mid = (low + high) / 2
if (A[mid] > value)
high = mid - 1
else if (A[mid] < value)
low = mid + 1
else
return mid // found
}
return -1 // not found
}
Tuttavia, se stai cercando il modo più veloce possibile, puoi impostare una tabella di ricerca basata sul sqrt (N-1)
dei tuoi numeri. Con solo 5.000 parole di memoria puoi ottenere ricerche O (1) in questo modo.
Spiegazione:
Poiché tutti i tuoi numeri hanno la forma N ^ 2 + 1 per un numero intero N da 1 a N, puoi creare una tabella di N elementi. L'elemento nella posizione i specificherà se i ^ 2 + 1 è nel tuo array o no. La tabella può essere implementata con un semplice array di lunghezza N. Ci vorrà O (N) per costruire e N parole di spazio. Ma una volta che hai il tavolo, tutte le ricerche sono O (1).
Esempio:
Ecco un codice di esempio in Python, che si legge come pseudocodice, come sempre :-)
import math
N = 5000
ar = [17, 26, 37, 50, 10001, 40001]
lookup_table = [0] * N
for val in ar:
idx = int(math.sqrt(val - 1))
lookup_table[idx] = 1
def val_exists(val):
return lookup_table[int(math.sqrt(val - 1))] == 1
print val_exists(37)
print val_exists(65)
print val_exists(40001)
print val_exists(90001)
La creazione della tabella occupa al massimo O (N) e le ricerche sono O (1).
Altri suggerimenti
log (n) per la ricerca binaria su c
Direi che è O (const)! :)
Dato un numero casuale r, è banale verificare se si tratta di un numero che potrebbe essere rappresentato nel modulo (n * n + 1). Basta controllare se sqrt (r-1) è un numero intero o no!
(Beh, potrebbe essere un po 'più complicato di così dato che il tuo linguaggio di programmazione può introdurre una certa complessità nella gestione di numeri interi o numeri in virgola mobile, ma comunque: non è necessario cercare l'array: controlla se il il numero è in questa forma particolare.)
Tecnicamente, la complessità di trovare un elemento in un array di dimensioni fisse è costante, poiché il log 2 5000 non cambierà.
La ricerca binaria è O (log n)
O (registro n) se l'array ha n elementi
Solo per espanderlo: sono lg n test, ovvero log 2 n. Questo lo rende O ( registro n) . Perché? perché ogni prova di una ricerca binaria divide la matrice a metà; quindi ci vogliono lg n prove.
Utilizzando una ricerca binaria, è tempo di ricerca Log (N).
bool ContainsBinarySearch(int[] array, int value) {
return Array.BinarySearch(arrray, value) >= 0;
}
In Perl:
Vorrei caricare i valori in un hash statico e quindi sarebbe O (1).
Crea l'hash di ricerca
lookup_hash {$ _} = 1 foreach (@original_array);
Sintassi di ricerca
($ lookup_hash {$ lookup_value}) & amp; & amp; print " Trovato in O (1) - nessun loop qui \ n " ;;