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).