Aggiornamento: vedi sotto per un aggiornamento sull'erroneità di questa operazione di join
Ecco uno schizzo molto approssimativo di una possibile soluzione:
Penso di poter avere una soluzione a questo problema usando un tipo di albero B + bilanciato in modo casuale. Come le melodie, questi alberi hanno una rappresentazione unica. A differenza dei melodi, memorizzano alcune chiavi più volte. Potrebbe essere possibile risolverlo usando un trucco di "Alberi di ricerca distorti" di Bent et al. Per memorizzare ogni chiave solo al livello più alto (cioè il più vicino alla radice) in cui appare)
Un albero per un set ordinato di valori univoci viene creato associando prima ogni valore a un flusso di bit, in modo simile al modo in cui ciascun valore in un treap è associato a una priorità. Ogni nodo nella struttura contiene sia una chiave che un flusso di bit. I nodi non foglia contengono inoltre un numero naturale che indica l'altezza dell'albero radicato in quel nodo. I nodi interni possono avere un numero di figli diverso da zero. Come B + -trees, ogni percorso non autointersecante dalla radice a una foglia ha la stessa lunghezza.
Ogni nodo interno contiene (come in B + -trees) la chiave più grande delle sue foglie discendenti. Ciascuno contiene anche un numero naturale indica l'altezza dell'albero con radice , e il flusso di bit associati con dalla esimo bit avanti. Se ogni chiave dell'albero è radicata ink i v k i + 1 v ha lo stesso primo bit nel suo flusso di bit, ogni figlio di v è una foglia e io è 1 . In caso contrario, i figli di v sono nodi interni che hanno tutti lo stesso mi esimo bit nel flusso di bit associato con la loro chiave.vKiovKi + 1vvio1vio
Per creare un albero da un elenco ordinato di chiavi con flussi di bit associati, innanzitutto raccogliere le chiavi in gruppi contigui in base al primo bit nei loro flussi. Per ciascuno di questi gruppi, crea un genitore con la chiave e il flusso di bit della chiave più grande del gruppo, ma elidendo il primo bit del flusso. Ora fai la stessa procedura di raggruppamento sui nuovi genitori per creare i nonni. Continua fino a quando rimane un solo nodo; questa è la radice dell'albero.
Il seguente elenco di chiavi e (inizio di) flussi di bit è rappresentato dall'albero sottostante. Nei prefissi del flusso di bit, un '.' significa un po '. Cioè, qualsiasi flusso di bit per la chiave A con uno 0 in primo luogo produce lo stesso albero di qualsiasi altro, supponendo che nessun flusso di bit di un'altra chiave sia diverso.
A 0...
B 00..
C 10..
D 0...
E 0011
F 1...
G 110.
H 0001
____H____
/ \
E H
| / \
__E__ G H
/ | \ | |
B C E G H
/ \ | / \ / \ |
A B C D E F G H
Ogni figlio di un particolare nodo interno ha lo stesso bit in primo luogo nel suo flusso di bit. Questo è chiamato il "colore" del genitore - 0 è rosso, 1 è verde. Il bambino ha un "sapore" a seconda del primo bit del suo flusso di bit - 0 è ciliegia, 1 è menta. Le foglie hanno sapori, ma nessun colore. Per definizione, un nodo ciliegia non può avere un genitore verde e un nodo conio non può avere un genitore rosso.
Supponendo che i bit nei flussi di bit siano IID della distribuzione uniforme, il PMF del numero di genitori di nodi è
2 1 - n ( n - 1n21 - n
e il valore atteso è(n+1)/2. Per tuttin≥2, questo è≤3( n - 1i - 1)( n + 1 ) / 2n ≥ 2, quindi l'altezza prevista dell'albero èO(lgn).≤ 34nO ( lgn )
Per unire due alberi di uguale altezza, per prima cosa controlla se le loro radici sono dello stesso colore. In tal caso, separa dalla radice sinistra il suo figlio più a destra e dalla radice destra il suo figlio più a sinistra, quindi unisci ricorsivamente questi due alberi. Il risultato sarà un albero della stessa altezza o uno più alto poiché gli alberi hanno lo stesso sapore (vedi sotto). Se il risultato dell'unione ricorsiva dei due alberi ha la stessa altezza dei due figli recisi, rendilo il figlio di mezzo di una radice con i figli rimanenti della radice sinistra prima di essa e i figli rimanenti della radice destra dopo di essa. Se è più alto di 1, fai dei suoi figli i figli di mezzo di una radice con i figli rimanenti della radice sinistra prima di essa e i figli rimanenti della radice destra dopo di essa. Se le radici hanno colori diversi, controlla se hanno lo stesso sapore. Se lo fanno, dare loro un nuovo genitore con la chiave e il flusso di bit della radice destra, eliminando il suo primo bit. In caso contrario, assegnare a ogni radice un nuovo genitore con la chiave e il flusso di bit della vecchia radice (eliminando ogni primo bit), quindi unire in modo ricorsivo quegli alberi.
Esistono due chiamate ricorsive in questo algoritmo. Il primo è quando le radici hanno lo stesso colore, il secondo è quando le radici hanno colori e sapori diversi. Le radici hanno lo stesso colore con probabilità . La chiamata ricorsiva in questo caso vede sempre radici con lo stesso sapore, quindi il secondo tipo di ricorsione non si verifica mai dopo il primo. Tuttavia, il primo può verificarsi più volte, ma ogni volta con probabilità 1 / 2 , quindi il tempo di attesa è ancora O ( 1 ) . La seconda chiamata ricorsiva accade con probabilità 1 / 41 / 21 / 2O ( 1 )1 / 4e le successive chiamate ricorsive sono sempre su alberi con colori diversi, quindi si applica la stessa analisi.
Per unire due alberi di altezza diversa, traccia prima la colonna vertebrale sinistra dell'albero destro, supponendo che l'albero destro sia più alto. (L'altro caso è simmetrico.) Quando vengono raggiunti due alberi di uguale altezza, eseguire l'operazione di unione per due alberi di uguale altezza, modificata come segue: Se il risultato ha la stessa altezza, sostituire l'albero che era un bambino con il risultato del join. Se il risultato è più alto, unisci il genitore dell'albero sulla destra alla radice dell'altro albero, dopo che è stato reso più alto da uno aggiungendo un genitore per la radice. L'albero sarà la stessa altezza con probabilità , quindi questo termina in O ( 1 ) previsto.
1 / 2O ( 1 )
O ( 1 )
a 01110
b 110..
c 10...
d 00000
L'albero fatto da [a,b]
ha altezza 2, l'albero fatto da [c,d]
ha altezza 2 e l'albero fatto da joinEqual (tree [a,b]) (tree [c,d])
ha altezza 3. Tuttavia, l'albero fatto da [a,b,c,d]
ha altezza 5.
Ecco il codice che ho usato per trovare questo errore .