rimozione di un numero e reinserendo tutti i suoi multipli (dai numeri primi nel set) in una coda di priorità è errata (nel senso della questione) - cioè produce sequenza corretta ma inefficientemente così.
È inefficiente in due modi: in primo luogo, lo sovrappone la sequenza; in secondo luogo, ogni operazione PriorityQueue comporta costi aggiuntivi (le operazioni remove_top
e insert
non sono in genere entrambe O (1), certamente non in qualsiasi implementazione PriorityQueue basata su elenco o struttura ad albero).
L'efficiente O (n) algoritmo mantiene puntatori indietro nella sequenza stessa in quanto viene prodotto, per trovare e aggiungere il numero successivo nella O (1). In pseudocodice:
return array h where
h[0]=1; n=0; ps=[2,3,5, ... ]; // base primes
is=[0 for each p in ps]; // indices back into h
xs=[p for each p in ps] // next multiples: xs[k]==ps[k]*h[is[k]]
repeat:
h[++n] := minimum xs
for each (i,x,p) in (is,xs,ps):
if(x==h[n])
{ x := p*h[++i]; } // advance the minimal multiple/pointer
Per ogni multiplo minimo avanza suo puntatore, mentre allo stesso tempo calcolandone il successivo valore multiplo.Questo implementa troppo efficacemente un PriorityQueue ma con distinzioni cruciali: è prima del il punto finale, non dopo; non crea alcuna memoria aggiuntiva tranne la sequenza stessa; e la sua dimensione è costante (solo k numeri, per k numeri primi) mentre la dimensione del PriorityQueue passato aumenta quando si progredisce lungo la sequenza (nel caso della sequenza Hamming, in base al set di numeri primi, come n 2/3, per n numeri della sequenza).
Il classico Hamming sequence in Haskell è essenzialmente lo stesso algoritmo:
h = 1 : map (2*) h `union` map (3*) h `union` map (5*) h
union [email protected](x:xs) [email protected](y:ys) = case compare x y of LT -> x : union xs b
EQ -> x : union xs ys
GT -> y : union a ys
Possiamo generare le smooth numbers per arbitrarie primi di base utilizzando la funzione foldi
(vedi Wikipedia) per ripiegare elenchi in un albero-like moda per l'efficienza, creando un albero di paragoni di dimensioni fisse:
smooth base_primes = h where -- strictly increasing base_primes NB!
h = 1 : foldi g [] [map (p*) h | p <- base_primes]
g (x:xs) ys = x : union xs ys
foldi f z [] = z
foldi f z (x:xs) = f x (foldi f z (pairs f xs))
pairs f (x:y:t) = f x y : pairs f t
pairs f t = t
È anche possibile calcolare direttamente una fetta sequenza Hamming attorno al suo n esimo in O (n 2/3) tempo, per enumerazione diretta di triplicare e valutare i loro valori attraverso i logaritmi, logval(i,j,k) = i*log 2+j*log 3+k*log 5
. Questo Ideone.com test entry calcola 1 billionth Hamming number in 1.12 0,05 secondi (2016/08/18: speedup principale causa di utilizzo di Int
posto di predefinito Integer
ove possibile, anche a 32 bit; ulteriore 20% grazie al ritocco suggerite dalla @GordonBGood, portando la complessità della dimensione della banda a O (n 1/3)).
Questo è discusso un po 'più in this answer dove troviamo anche la sua piena attribuzione:
slice hi w = (c, sortBy (compare `on` fst) b) where -- hi is a top log2 value
lb5=logBase 2 5 ; lb3=logBase 2 3 -- w<1 (NB!) is (log2 width)
(Sum c, b) = fold -- total count, the band
[ (Sum (i+1), -- total triples w/this j,k
[ (r,(i,j,k)) | frac < w ]) -- store it, if inside the band
| k <- [ 0 .. floor (hi /lb5) ], let p = fromIntegral k*lb5,
j <- [ 0 .. floor ((hi-p)/lb3) ], let q = fromIntegral j*lb3 + p,
let (i,frac) = pr (hi-q) ; r = hi - frac -- r = i + q
] -- (sum . map fst &&& concat . map snd)
pr = properFraction
Questo può essere generalizzato per k base di numeri primi e, probabilmente, in esecuzione in O (n (k -1)/k) tempo.
vedere this SO entry per un importante sviluppo successivo. inoltre, this answer è interessante. e un altro related answer.
Meglio chiedere questo su math.stackexchange.com –
@HighPerformanceMark sì, ma in ordine crescente – nims
Dai un'occhiata a questa [domanda correlata] (http://stackoverflow.com/questions/7333657/how-to-generate-numbers -given-loro-prime-fattori-ma-con-Unknow-esponenti). La risposta accettata fornisce un codice O (n) Python simile alla mia risposta qui, che può essere adattato a "basi" arbitrarie (set di numeri primi). –