Quando scegliere l'albero RB, l'albero B o l'albero AVL?


88

Come programmatore, quando dovrei considerare di utilizzare un albero RB, un albero B o un albero AVL? Quali sono i punti chiave da considerare prima di decidere sulla scelta?

Qualcuno può spiegare con uno scenario per ogni struttura ad albero perché viene scelto rispetto ad altri con riferimento ai punti chiave?


10
Bene, io per primo apprezzo questa domanda - attualmente presentata con una scelta di Fastutil IntAVLTreeSet vs IntRBTreeSet.
Yang

Risposte:


114

Prendilo con un pizzico di sale:

B-tree quando gestisci più di migliaia di elementi e li stai pagando da un disco o da un supporto di archiviazione lento.

RB tree quando si eseguono inserimenti, eliminazioni e recuperi abbastanza frequenti dall'albero.

Albero AVL quando gli inserimenti e le eliminazioni sono poco frequenti rispetto ai recuperi.


34
Solo per aggiungere qualche dettaglio in più: gli alberi B possono avere un numero variabile di figli che gli consentono di contenere molti record ma mantengono comunque un albero di altezza ridotta. RB Tree ha regole meno rigide sul ribilanciamento che rendono gli inserimenti / eliminazioni più veloci dell'albero AVL. Al contrario, l'albero AVL è più strettamente bilanciato, quindi le ricerche sono più veloci dell'albero RB.
pschang

Gli alberi RB hanno anche prestazioni migliori O (1) sul ribilanciamento che li rende più adatti a strutture dati persistenti con roll-back e roll-forward.

20

Penso che gli alberi B + siano una buona struttura di dati del contenitore ordinata per scopi generali, anche nella memoria principale. Anche quando la memoria virtuale non è un problema, spesso lo è l'ottimizzazione della cache e gli alberi B + sono particolarmente utili per l'accesso sequenziale: le stesse prestazioni asintotiche di un elenco collegato, ma con l'ottimizzazione della cache vicina a un semplice array. Tutto questo e O (log n) cerca, inserisci e cancella.

Gli alberi B + hanno problemi, tuttavia, come gli elementi che si spostano all'interno dei nodi quando si inseriscono / cancellano, invalidando i puntatori a quegli elementi. Ho una libreria contenitore che esegue la "manutenzione del cursore": i cursori si collegano al nodo foglia a cui fanno attualmente riferimento in un elenco collegato, in modo che possano essere corretti o invalidati automaticamente. Poiché raramente ci sono più di uno o due cursori, funziona bene, ma è comunque un po 'di lavoro in più.

Un'altra cosa è che l'albero B + è essenzialmente proprio questo. Immagino che tu possa rimuovere o ricreare i nodi non foglia a seconda che tu ne abbia bisogno o meno, ma con i nodi binari dell'albero ottieni molta più flessibilità. Un albero binario può essere convertito in un elenco collegato e viceversa senza copiare i nodi: basta cambiare i puntatori e poi ricordare che ora lo stai trattando come una struttura dati diversa. Tra le altre cose, questo significa che si ottiene una fusione O (n) abbastanza semplice di alberi: converti entrambi gli alberi in elenchi, uniscili, quindi riconvertili in un albero.

Un'altra cosa è l'allocazione e la liberazione della memoria. In un albero binario, questo può essere separato dagli algoritmi: l'utente può creare un nodo, quindi chiamare l'algoritmo di inserimento e le eliminazioni possono estrarre i nodi (scollegarli dall'albero, ma non liberare la memoria). In un albero B o B +, questo ovviamente non funziona: i dati vivranno in un nodo multi-elemento. Scrivere metodi di inserimento che "pianificano" l'operazione senza modificare i nodi fino a quando non sanno quanti nuovi nodi sono necessari e che possono essere allocati è una sfida.

Rosso nero contro AVL? Non sono sicuro che faccia una grande differenza. La mia libreria ha una classe "strumento" basata su policy per manipolare i nodi, con metodi per elenchi a doppio collegamento, alberi binari semplici, alberi splay, alberi rosso-neri e treap, comprese varie conversioni. Alcuni di questi metodi sono stati implementati solo perché prima o poi mi annoiavo. Non sono nemmeno sicuro di aver testato i metodi treap. Il motivo per cui ho scelto alberi rosso-neri piuttosto che AVL è perché personalmente capisco meglio gli algoritmi, il che non significa che siano più semplici, è solo un colpo di fortuna della storia che conosco meglio.

Un'ultima cosa: originariamente ho sviluppato i miei contenitori per alberi B + solo come esperimento. È uno di quegli esperimenti che non sono mai finiti davvero, ma non è qualcosa che incoraggerei gli altri a ripetere. Se tutto ciò di cui hai bisogno è un contenitore ordinato, la risposta migliore è usare quello fornito dalla tua libreria esistente, ad esempio std :: map ecc. In C ++. La mia libreria si è evoluta nel corso degli anni, ci è voluto un po 'di tempo per renderla stabile e ho scoperto relativamente di recente che è tecnicamente non portabile (dipende da un comportamento indefinito WRT offsetof).



0

Quando si scelgono le strutture dati, si scambiano fattori come

  • velocità di recupero v velocità di aggiornamento
  • come la struttura affronta le operazioni peggiori, ad esempio l'inserimento di record che arrivano in un ordine ordinato
  • spazio sprecato

Inizierei leggendo gli articoli di Wikipedia a cui fa riferimento Robert Harvey.

Pragmaticamente, quando si lavora in linguaggi come Java, il programmatore medio tende a utilizzare le classi di raccolta fornite. Se in un'attività di ottimizzazione delle prestazioni si scopre che le prestazioni della raccolta sono problematiche, è possibile cercare implementazioni alternative. Raramente è la prima cosa che uno sviluppo guidato dall'azienda deve considerare. È estremamente raro che sia necessario implementare manualmente tali strutture di dati, di solito ci sono librerie che possono essere utilizzate.


1
Per essere onesti, OP ha chiesto when should I consider using, no when should I consider implementing. Sebbene l'ultimo paragrafo sia vero, non fornisce molto valore nel contesto di questa domanda. Anche con le librerie, è necessario comprendere gli algoritmi per scegliere in modo efficace quale struttura si adatta meglio alle proprie esigenze aziendali.
Dan Bechard
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.