Myślę, że drzewa B + to dobra uporządkowana struktura danych ogólnego przeznaczenia, nawet w pamięci głównej. Nawet jeśli pamięć wirtualna nie jest problemem, często jest ona przyjazna dla pamięci podręcznej, a drzewa B + są szczególnie dobre dla dostępu sekwencyjnego - ta sama asymptotyczna wydajność, jak połączona lista, ale z przyjaznością dla pamięci podręcznej zbliżoną do prostej tablicy. Wszystko to i O (log n) szukaj, wstaw i usuń.
B + drzewa mają jednak problemy - takie jak elementy poruszające się w obrębie węzłów podczas wstawiania/usuwania, unieważniające wskaźniki do tych elementów. Mam bibliotekę kontenerów, która wykonuje "obsługę kursora" - kursory dołączają się do węzła z listkami, do którego aktualnie odwołują się na liście połączonej, aby można je było naprawić lub unieważnić automatycznie. Ponieważ rzadko jest więcej niż jeden lub dwa kursory, działa dobrze - ale to jeszcze trochę więcej pracy.
Inną rzeczą jest to, że drzewo B + jest w zasadzie tym właśnie. Sądzę, że możesz odciąć lub odtworzyć węzły inne niż liście w zależności od tego, czy ich potrzebujesz, czy nie, ale w przypadku węzłów drzewa binarnego zyskujesz większą elastyczność. Drzewo binarne można przekonwertować na listę połączoną iz powrotem bez kopiowania węzłów - wystarczy zmienić wskaźniki, a następnie pamiętać, że traktuje się je teraz jako inną strukturę danych. Między innymi oznacza to, że masz dość łatwe O (n) łączenie drzew - konwertuj oba drzewa na listy, scalaj je, a następnie konwertuj z powrotem do drzewa.
Kolejną rzeczą jest przydzielanie i uwalnianie pamięci.W drzewie binarnym można to oddzielić od algorytmów - użytkownik może utworzyć węzeł, a następnie wywołać algorytm wstawiania, a usuwanie może wyodrębnić węzły (odłączyć je od drzewa, ale nie zwalniać pamięci). W drzewie B lub w drzewie B + to oczywiście nie działa - dane będą żyły w węźle z wieloma elementami. Pisanie metod wstawiania, które "planują" operację bez modyfikowania węzłów, dopóki nie będą wiedzieć, ile nowych węzłów jest potrzebnych i które mogą być przydzielone, jest wyzwaniem.
Czerwony czarny kontra AVL? Nie jestem pewien, czy robi to wielką różnicę. Moja własna biblioteka ma oparte na regułach "narzędzie" klasy do manipulowania węzłami, z metodami podwójnie połączonych list, prostych drzew binarnych, drzewek rozrzuconych, drzewek czerwono-czarnych i zawrotów, w tym różnych konwersji. Niektóre z tych metod zostały wdrożone tylko dlatego, że nudziłem się w tym samym czasie. Nie jestem pewien, czy testowałem nawet metody treap. Powodem, dla którego wybrałem czerwono-czarne drzewa, a nie AVL, jest to, że ja osobiście lepiej rozumiem algorytmy - co nie znaczy, że są prostsze, to tylko fiołek historii, że lepiej się z nimi zapoznałem.
Ostatnia rzecz - Pierwotnie opracowałem moje kontenery drzewa B + jako eksperyment. To jeden z tych eksperymentów, który nigdy się nie zakończył, ale nie jest to coś, co zachęciłbym innych do powtórzenia. Jeśli wszystko czego potrzebujesz to uporządkowany kontener, najlepszą odpowiedzią jest użycie tej, którą zapewnia twoja istniejąca biblioteka - np. std :: map etc w C++. Moja biblioteka ewoluowała przez lata, zajęło to sporo czasu, zanim stała się stabilna, a stosunkowo niedawno odkryłem, że jest technicznie nieprzenośna (w zależności od nieokreślonego zachowania WRT).
Cóż, ja na przykład doceniam to pytanie - obecnie prezentowane z wyborem fastutil IntAVLTreeSet vs. IntRBTreeSet. – Yang