Sottosistema di un albero rosso e nero


14

Mentre cercavo di correggere un bug in una libreria, ho cercato documenti per trovare subrange su alberi rossi e neri senza successo. Sto prendendo in considerazione una soluzione che utilizza le cerniere lampo e qualcosa di simile alla solita operazione di aggiunta utilizzata sugli algoritmi di eliminazione per strutture di dati immutabili, ma mi chiedo ancora se esiste un approccio migliore che non sono riuscito a trovare, o anche un limite minimo di complessità su tale operazione?

Per essere chiari, sto parlando di un algoritmo che, dato un albero rosso e nero e due confini, produrrà un nuovo albero rosso e nero con tutti gli elementi del primo albero che appartengono a tali confini.

Naturalmente, un limite superiore per la complessità sarebbe la complessità di attraversare un albero e costruirne un altro aggiungendo elementi.


3
@Radu: c'è un bug nella funzione di modifica dei commenti. Se usi il lattice in un commento e modifichi il commento, vedi un comportamento strano, come la duplicazione ecc.
Aryabhata,

@Radu Ho aggiunto un paio di paragrafi per spiegare meglio la mia domanda.
Daniel C. Sobral,

Gli alberi sono immutabili?
Tsuyoshi Ito,

Inoltre, intendevi il limite superiore anziché il limite inferiore nell'ultimo paragrafo?
Tsuyoshi Ito,

2
Sembra che l'operazione di divisione su alberi rosso-neri possa essere implementata nel tempo peggiore O (log n), dove n è il numero di elementi in un albero. Questa affermazione può essere trovata nell'introduzione del documento "Elenchi ordinabili catenabili a tempo costante puramente funzionale nel caso peggiore" di Gerth Stølting Brodal, Christos Makris e Kostas Tsichlas, ESA 2006: cs.au.dk/~gerth/pub/esa06trees.html . Come ho già detto nel mio commento precedente, ciò consente un'implementazione nel tempo peggiore O (log n) dell'operazione subrange.
Tsuyoshi Ito,

Risposte:


10

Questa risposta combina alcuni dei miei commenti alla domanda e li espande.

L'operazione subrange su alberi rosso-neri può essere eseguita nel caso O (log n) nel caso peggiore, dove n è il numero di elementi nella struttura originale. Poiché l'albero risultante condividerà alcuni nodi con l'albero originale, questo approccio è adatto solo se gli alberi sono immutabili (o gli alberi sono mutabili ma l'albero originale non è più necessario).

Si noti innanzitutto che l'operazione subrange può essere implementata da due operazioni split. Qui l' operazione di divisione prende un albero rosso-nero T e un tasto x e produce due alberi L e R in modo tale che L sia costituito da tutti gli elementi di T minori di x e R gli elementi di T maggiori di x. Pertanto, il nostro obiettivo ora è implementare l'operazione di divisione su alberi rosso-neri nel tempo O (log n) nel peggiore dei casi.

Come eseguiamo l'operazione di divisione su alberi rosso-neri in O (log n) time? Bene, si è scoperto che esisteva un metodo ben noto. (Non lo sapevo, ma non sono esperto di strutture di dati.) Considera l' operazione di join , che prende due alberi L e R in modo tale che ogni valore in L sia inferiore a ogni valore in R e produca un albero costituito da tutti i valori in L e R. L'operazione di join può essere implementata nel tempo peggiore O (| r L −r R | +1), dove r L e r Rsono i ranghi di L e R, rispettivamente (ovvero il numero di nodi neri sul percorso dalla radice a ciascuna foglia). L'operazione di divisione può essere implementata utilizzando l'operazione O (log n) volte dell'operazione di join e il tempo totale nel caso peggiore è ancora O (log n) considerando una somma telescopica.

Le sezioni 4.1 e 4.2 di un libro [Tar83] di Tarjan descrivono come implementare le operazioni di join e split su alberi rosso-neri nel peggiore dei casi O (log n). Queste implementazioni distruggono gli alberi originali, ma è facile convertirle in implementazioni immutabili e funzionali copiando i nodi invece di modificarli.

Come nota a margine, i moduli Set e Map di Objective Caml forniscono le operazioni split e altre operazioni standard su (immutabili) alberi di ricerca binari bilanciati. Sebbene non utilizzino alberi rosso-neri (usano alberi di ricerca binari bilanciati con il vincolo che l'altezza sinistra e l'altezza destra differiscono al massimo per 2), anche guardare le loro implementazioni potrebbe essere utile. Ecco l'implementazione del modulo Set .

Riferimenti

[Tar83] Robert Endre Tarjan. Strutture dati e algoritmi di rete . Volume 44 della serie di conferenze regionali CBMS-NSF in Matematica applicata , SIAM, 1983.


@Radu GRIGore: Sì, a meno che non mi manchi qualcosa.
Tsuyoshi Ito,

@Radu GRIGore: O forse no, ora non ne sono sicuro. Questa implementazione dell'operazione split alloca O (log n) nuovi nodi per l'albero di output, ma penso che l'intera operazione possa probabilmente essere implementata in modo ricorsivo di coda, richiedendo solo O (1) spazio di lavoro. Se questo è corretto, la risposta alla tua domanda dipenderà da cosa intendi per "spazio extra".
Tsuyoshi Ito,

@Radu GRIGore: In tal caso, penso che lo spazio extra sia O (1), anche se non l'ho verificato attentamente.
Tsuyoshi Ito,

@Radu GRIGore: non riesco a vedere il motivo per cui uno si preoccupa della quantità di spazio di lavoro senza preoccuparsi della quantità di spazio necessario per memorizzare il risultato stesso. Nella teoria della complessità, il problema di solito specifica quale sia il risultato e quindi lo spazio necessario per archiviare il risultato non dipende dagli algoritmi. Tuttavia, nel problema attuale, ci sono molti modi per implementare l'operazione richiesta e alcune implementazioni hanno bisogno di più spazio per memorizzare il risultato di altre. Se ignori la differenza di questa quantità di spazio, non vedo perché ti preoccupi di quanto spazio di lavoro abbiamo bisogno.
Tsuyoshi Ito,

Il problema per gli alberi immutabili è diverso da quello per gli alberi mutabili. Capisco la differenza, quindi non avevo nulla da chiedere al riguardo. Ora, ingrandendo uno dei due problemi, ci sono due aspetti da discutere: memoria e tempo. Non hai detto quanta memoria usi e non mi è sembrato ovvio quale sia la risposta, così ho chiesto. Non riesco a vedere come questo ti abbia fatto pensare che ignoro la differenza tra i due problemi.
Radu GRIGore,

8

La soluzione non è usare alberi rosso-neri. Negli alberi splay e negli alberi AVL il codice per la divisione e l'unione è molto semplice. Ti rimando ai seguenti URL con codice java per alberi di visualizzazione e alberi AVL che supportano questo. Vai al seguente URL e controlla Set.java (alberi avl) e SplayTree.java (alberi splay).

ftp://ftp.cs.cmu.edu/usr/ftp/usr/sleator/splaying/

--- Danny Sleator


5
Benvenuti nel sito, Danny!
Suresh Venkat,

2
In che modo ciò contribuirà a modificare l'implementazione di Scala Red Black per supportare il subranging in meno di O(n)? Non ho chiesto che tipo di alberi hanno implementazioni subrange semplici perché questo non è un problema che ho. Questa risposta, sebbene ben intenzionata, è fuori tema e inutile per il problema in questione.
Daniel C. Sobral,

6

(Questo dovrebbe essere un commento, ma sono troppo nuovo per lasciare un commento.)

Voglio solo notare che potresti anche essere interessato all'operazione di "escissione", che restituisce il sottorange come un nuovo albero e l'albero di input senza il sottorange come un altro. È necessario avere il controllo sulla rappresentazione sottostante dell'albero, poiché il metodo noto si basa su collegamenti di livello. L'escissione corre nel tempo logaritmica alla dimensione dell'albero più piccolo , sebbene in senso ammortizzato ("ammortizzato" è iirc, perché non ho più accesso al foglio) Vedi:

K. Hoffman, K. Mehlhorn, P. Rosenstiehl e RE Tarjan, Ordinamento delle sequenze della Giordania in tempo lineare utilizzando alberi di ricerca collegati a livello, Informazioni e controllo, 68 (1986), 170–184

PS La citazione di cui sopra proviene dalla scrittura di melodia di Seidel. I melodi supportano anche l'escissione.


Questo metodo presuppone che uno abbia già dei puntatori (o "dita") sui due confini.
jbapple,

3

nm[un',B]

  1. O(lgn)un'un'
  2. O(m)
  3. O(m)

O(m+lgn)O(n+mlgm)

o(m)Ω(lgm)Klgm

Non ho elaborato i dettagli, quindi non sono sicuro di come la contabilità aggiuntiva influenzi il tempo di esecuzione.

O(1)Ω(lgm)


Pensando a questo, penso che potrei fare un conteggio approssimativo O(logn), con il quale potrei evitare l'array temporaneo.
Daniel C. Sobral,

Puoi ottenere il conteggio in O (lg n) memorizzando le dimensioni delle sottostrutture nelle loro radici.
Radu GRIGore,

... ma l'archiviazione delle dimensioni nei nodi va contro il requisito di non utilizzare lo spazio ausiliario, quindi la mia osservazione non affronta la tua preoccupazione per la memoria.
Radu GRIGore,

1
Gli alberi binari possono essere perfettamente riequilibrati utilizzando solo lo spazio aggiuntivo COSTANTE (oltre all'albero stesso): eecs.umich.edu/~qstout/abs/CACM86.html
Jeffε

O(m+lgn)O(1)
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.