Devo calcolare la mediana corrente:
Input: , , vettore .( x 1 , x 2 , … , x n )
Output: vettore , dove è la mediana di .y i ( x i , x i + 1 , … , x i + k - 1 )
(Nessun imbroglio con approssimazioni; vorrei avere soluzioni esatte. Gli elementi sono numeri interi grandi).
Esiste un banale algoritmo che mantiene un albero di ricerca di dimensioni ; il tempo di esecuzione totale è . (Qui un "albero di ricerca" si riferisce ad una struttura dati efficiente che supporta inserimenti, eliminazioni e query mediane nel tempo logaritmico.)O ( n log k )
Tuttavia, questo mi sembra un po 'stupido. Impareremo efficacemente tutte le statistiche degli ordini in tutte le finestre di dimensione , non solo le mediane. Inoltre, ciò non è troppo attraente in pratica, specialmente se è grande (i grandi alberi di ricerca tendono ad essere lenti, i costi di gestione della memoria non sono banali, l'efficienza della cache è spesso scarsa, ecc.).k
Possiamo fare qualcosa di sostanzialmente migliore?
Esistono limiti inferiori (ad esempio, l'algoritmo banale è asintoticamente ottimale per il modello di confronto)?
Modifica: David Eppstein ha dato un bel limite inferiore per il modello di confronto! Mi chiedo se sia comunque possibile fare qualcosa di leggermente più intelligente dell'algoritmo banale?
Ad esempio, possiamo fare qualcosa in tal senso: dividere il vettore di input in parti di dimensione ; ordina ogni parte (tenendo traccia delle posizioni originali di ciascun elemento); e quindi utilizzare il vettore ordinato a tratti per trovare in modo efficiente le mediane in esecuzione senza alcuna struttura di dati ausiliaria? Ovviamente questo sarebbe ancora , ma in pratica gli array di ordinamento tendono ad essere molto più veloci rispetto al mantenimento degli alberi di ricerca.O ( n log k )
Modifica 2: Saeed voleva vedere alcuni motivi per cui penso che l'ordinamento sia più veloce delle operazioni dell'albero di ricerca. Ecco alcuni benchmark molto rapidi, per , : n = 10 8
- ≈ 8s: ordinamento di vettori con elementi ciascunok
- ≈ 10s: ordinamento di un vettore con elementi
- ≈ 80: inserimenti ed eliminazioni in una tabella hash di dimensionik
- ≈ 390s: inserimenti ed eliminazioni in un albero di ricerca bilanciato di dimensionik
La tabella hash è lì solo per il confronto; non ha alcuna utilità diretta in questa applicazione.
In sintesi, abbiamo quasi una differenza di fattore 50 nelle prestazioni dell'ordinamento rispetto alle operazioni dell'albero di ricerca bilanciata. E le cose peggiorano molto se aumentiamo .
(Dettagli tecnici: Dati = numeri interi casuali a 32 bit. Computer = un tipico laptop moderno. Il codice di test è stato scritto in C ++, usando le routine di libreria standard (std :: sort) e le strutture di dati (std :: multiset, std :: unsorted_multiset). Ho usato due diversi compilatori C ++ (GCC e Clang) e due diverse implementazioni della libreria standard (libstdc ++ e libc ++). Tradizionalmente, std :: multiset è stato implementato come un albero rosso-nero altamente ottimizzato.)