Unione più rapida di strutture dati simili a treap con approssimativamente le stesse dimensioni


16

Dati due alberi AVL e e un valore tale che , è facile costruire un nuovo albero AVL contenente e i valori in e nel tempo , dove indica l'altezza di un albero (purché gli alberi memorizzino la loro altezza).T1t rx T 1 , y T 2 , x < t r < y t r T 1 T 2 O ( 1 + | h ( T 1 ) - h ( T 2 ) | ) h ( T ) TT2trxT1,yT2,x<tr<ytrT1T2O(1+|h(T1)h(T2)|)h(T)T

Questo è possibile anche per alberi rosso-neri e presumo anche molti altri tipi di alberi bilanciati.

Questo è possibile per strutture dati simili a treap o treap? E se lasciamo fuori ?tr

La carta dei trattati in Algorithmica mostra come farlo in tempo previsto. Se esiste un modo per eseguire O (1) atteso join su treap (o strutture di dati simili a treap) con all'incirca le stesse dimensioni (o priorità di root), penso che potrebbe essere possibile usare un trucco di Kaplan e Tarjan del bootstrap le spine al fine di creare melodie (o strutture di dati simili a quelle del treap) con join doppiamente logaritmico.O(min(h(T1),h(T2)))


Ecco un po 'di codice Haskell che ho scritto che mostra un join rapido di alberi AVL con approssimativamente le stesse dimensioni: haskell.pastebin.com/nfGV8Ffz
jbapple

Dubito che sia possibile, perché sembra (senza una prova) che la profondità attesa del nuovo nodo (contenente il valore t_r) sia più che una costante anche nel caso in cui h (T_1) = h (T_2).
Tsuyoshi Ito,

Tsuyoshi Ito: Sono d'accordo, se assegni una priorità al nuovo nodo allo stesso modo in cui assegni le priorità ad altri nodi. E se gli assegnassi una priorità garantita superiore a quella dei nodi radice? Ciò distrugge la natura IID delle priorità, ma cosa succede se poi si segnano le altre priorità come spostate, in qualche modo, come i percorsi negli alberi rosso-neri persistenti vengono contrassegnati agli endpoint? O cosa succede se si memorizzano i valori solo nelle foglie di un treap e si esegue un join senza un t_r?
jbapple,

I nodi in melodie con n discendenti hanno lasciato i discendenti con probabilità 1 / n. Ciò può contribuire ai lunghi tempi di fusione anche per passaggi di dimensioni uguali: selezionare una nuova radice richiede di navigare su di essa, che, poiché la profondità media dell'albero è Theta (lg n), richiede anche tempo Theta (lg n). Che cosa succede se un nodo di treap con n discendenti ha lasciato i bambini con probabilità (n scelgo i) / 2 ^ n e i valori sono memorizzati solo su foglie come in un albero B +. Quindi unendo due ridistribuiti equamente ridistribuisce un piccolo numero di elementi da un albero all'altro in attesa.
jbapple,

Se i miei calcoli sono corretti, il numero previsto di elementi ridistribuiti è Theta (sqrt n), che, supponendo che tutto il resto possa essere elaborato (come la proprietà di ricerca delle dita), richiederebbe comunque Theta (lg n) tempo in attesa. Che ne dici di usare una distribuzione ancora più stretta?
jbapple,

Risposte:


3

No, non è possibile farlo con i normali Treaps se le priorità sono casuali.

L'affermazione precisa che farò è che per eseguire tale fusione su due trattati di dimensioni uguali con priorità casuali è necessario aggiornare i puntatori in previsione.Θ(logn)

Ecco uno schizzo di prova approssimativo:

Considera il numero di puntatori che devi modificare nell'aspettativa di eseguire l'operazione. È più semplice provare un limite di se non inseriamo ma uniamo e . Considera la colonna vertebrale destra di e la colonna vertebrale sinistra di . Colora gli elementi di rosso e quelli di blu. Ordina per priorità. Dobbiamo cambiare un puntatore ogni volta che il colore cambia in questa sequenza. Poiché entrambe le spine hanno dimensionet r T 1 T 2 S 1 T 1 S 2 T 2 S 1 S 2 S 1S 2 Θ ( log n ) Θ ( log n ) Θ ( log n ) t rΘ(logn)trT1T2S1T1S2T2S1S2S1S2Θ(logn)con alta probabilità e le priorità sono casuali, non è troppo difficile vedere che il numero di cambi di colore nella sequenza è anche . Quindi abbiamo bisogno di aggiornare i puntatori per l'unione (senza aggiungere ).Θ(logn)Θ(logn)tr

Ora, aggiungere mentre si fa l'unione non aiuta molto. Il numero di modifiche al puntatore in quel caso può essere limitato come segue: Ordinare base alla priorità. Elimina tutto meno di nella sequenza. Quindi il numero di cambi di colore nella sequenza risultante è il nostro limite inferiore. Poiché ha priorità casuale, l'altezza prevista del sottostruttura radicata ad esso nel passo finale è , quindi ha solo nodi di con priorità inferiore rispetto ad essa in attesa, quindi abbiamo perso solo il puntatore cambia nel limite inferiore quando si aggiunge .S 1S 2{ t r } t r t r O ( 1 ) O ( 1 ) S 1S 2 O ( 1 ) t rtrS1S2{tr}trtrO(1)O(1)S1S2O(1)tr

Ora, detto questo, probabilmente c'è un modo per ottenere una struttura di dati "simili a treap" che consente fusioni di tempo attese costanti.


Sì, sto cercando una struttura di dati "simile a una melodia". Anche se ho menzionato tanto nei commenti e nella mia risposta defunta, non l'ho inserito nel titolo o nella domanda.
jbapple

Grazie per la tua risposta. Ho modificato il titolo e il testo della domanda in modo da essere meno ambiguo.
jbapple

1

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.vKiovKio+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 tuttin2, questo è3(n-1io-1)(n+1)/2n2, 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 .

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.