Sembra che ovunque io guardi, le strutture di dati vengono implementate usando alberi rosso-neri ( std::set
in C ++, SortedDictionary
in C #, ecc.)
Avendo appena coperto (a, b), alberi rosso-nero e AVL nella mia classe di algoritmi, ecco cosa sono uscito (anche chiedendo in giro professori, sfogliando alcuni libri e google un po '):
- Gli alberi AVL hanno una profondità media inferiore rispetto agli alberi rosso-neri, quindi la ricerca di un valore nell'albero AVL è sempre più veloce.
- Gli alberi rosso-neri apportano meno modifiche strutturali per bilanciarsi rispetto agli alberi AVL, il che potrebbe renderli potenzialmente più veloci per l'inserimento / l'eliminazione. Sto dicendo potenzialmente, perché ciò dipenderebbe dal costo della modifica strutturale all'albero, poiché ciò dipenderà molto dal tempo di esecuzione e dall'attuazione (potrebbe anche essere completamente diverso in un linguaggio funzionale quando l'albero è immutabile?)
Esistono molti parametri di riferimento online che mettono a confronto gli alberi AVL e rosso-nero, ma ciò che mi ha colpito è che il mio professore sostanzialmente ha detto che di solito avresti fatto una delle due cose:
- O non ti interessa molto delle prestazioni, nel qual caso la differenza del 10-20% di AVL rispetto al rosso-nero nella maggior parte dei casi non importa affatto.
- Oppure ti preoccupi davvero delle prestazioni, nel qual caso dovresti abbandonare sia gli alberi AVL che gli alberi rosso-nero e andare con gli alberi B, che possono essere modificati per funzionare molto meglio (o (a, b) -trees, I ' Metterò tutti quelli nello stesso paniere.)
Il motivo è che un albero B archivia i dati in modo più compatto nella memoria (un nodo contiene molti valori) e ci saranno molti meno errori nella cache. È inoltre possibile modificare l'implementazione in base al caso d'uso e far dipendere l'ordine dell'albero B dalla dimensione della cache della CPU, ecc.
Il problema è che non riesco a trovare quasi nessuna fonte in grado di analizzare l'utilizzo nella vita reale di diverse implementazioni di alberi di ricerca su hardware moderno reale. Ho esaminato molti libri sugli algoritmi e non ho trovato nulla che potesse confrontare insieme diverse varianti di alberi, oltre a mostrare che uno ha una profondità media inferiore rispetto all'altro (il che non dice molto su come si comporterà l'albero in programmi reali.)
Detto questo, c'è un motivo particolare per cui gli alberi rosso-neri vengono usati ovunque, quando in base a quanto detto sopra, gli alberi B dovrebbero essere più performanti? (poiché l'unico punto di riferimento che ho trovato mostra anche http://lh3lh3.users.sourceforge.net/udb.shtml , ma potrebbe trattarsi solo di un'implementazione specifica). O è il motivo per cui tutti usano alberi rosso-neri perché sono piuttosto facili da implementare o, in altre parole, difficili da implementare male?
Inoltre, come cambia questo quando ci si sposta nel regno dei linguaggi funzionali? Sembra che sia Clojure che Scala utilizzino i tentativi mappati di array Hash , dove Clojure utilizza un fattore di ramificazione di 32.