Dlaczego std :: map zaimplementowany jako drzewo czerwono-czarne?

głosy
130

Dlaczego std :: map zaimplementowany jako drzewo czerwono-czarne ?

Istnieje kilka zrównoważone binarne drzewa wyszukiwania (BSTS) tam. Jakie były projektowe kompromisów w wyborze drzewo czerwono-czarne?

Utwórz 13/03/2011 o 09:33
źródło użytkownik
W innych językach...                            


6 odpowiedzi

głosy
86

Prawdopodobnie dwa najbardziej popularne algorytmy drzewo bilansowania siebie są czerwono-czarny drzew i AVL drzew . Aby zrównoważyć drzewo po wstawiania / aktualizacji oba algorytmy wykorzystać pojęcie obrotów gdzie węzły drzewa są obracane w celu przeprowadzenia ponownego zrównoważenia.

Chociaż w obu algorytmów insert / delete operacje O (log n), w przypadku czerwono-czarny rotacja drzewa ponownego równoważenia jest O (1) operacja natomiast z AVL to O (log n) operacji, dzięki czemu drzewo czerwono-czarne bardziej skuteczny w tym aspekcie ponownego równoważenia sceny i jeden z możliwych powodów, że jest powszechnie stosowane.

Czerwono-czarne drzewa są wykorzystywane w większości bibliotek zbiórki, w tym ofiar z Java i Microsoft .NET Framework.

Odpowiedział 13/03/2011 o 09:47
źródło użytkownik

głosy
2

Jest to po prostu wybór implementacji - one mogą być realizowane jako dowolny zrównoważonego drzewa. Poszczególne opcje są porównywalne z niewielkimi różnicami. Dlatego każdy jest tak dobra, jak każda inna.

Odpowiedział 13/03/2011 o 09:48
źródło użytkownik

głosy
22

AVL drzew mają maksymalną wysokość 1.44logn, natomiast RB drzewa mają maksymalnie 2logn. Wstawianie elementu w AVL może oznaczać zrównoważenia w jednym punkcie w drzewie. Zrównoważenia zakończeniu wkładania. Po wstawieniu nowego liścia, aktualizowanie przodków tego liścia musi być zrobione do korzenia, lub aż do punktu, w którym dwa poddrzewa są jednakowej głębokości. Prawdopodobieństwo konieczności aktualizacji k węzłów 1/3 ^ K. Zrównoważenie O (1). Usuwanie elementu może oznaczać więcej niż jeden zrównoważenia (do połowy głębokości drzewa).

RB-B-drzewa są drzewa o uporządkowaniu 4 reprezentowane jako binarne drzewo poszukiwań. Pochodna 4-węzeł B Wyniki drzewa w dwóch poziomach równoważnych BST. W najgorszym przypadku, wszystkie węzły drzewa są 2-węzłów, z jednym tylko łańcuchu 3-węzłów w dół do liścia. Że liść będzie w odległości 2logn od korzenia.

Schodząc z korzenia do punktu wstawiania, trzeba zmienić 4 węzły na 2-węzłów, aby upewnić się, że każde wprowadzenie nie będzie nasycić liściu. Wracając z wstawki, wszystkie węzły te muszą być analizowane, aby upewnić się, że prawidłowo reprezentować 4 węzły. Można to również zrobić zejście w drzewie. Globalny koszt będzie taki sam. Nie ma darmowego lunchu! Usuwanie elementu z drzewa jest tego samego rzędu.

Wszystkie te drzewa wymagają węzły niosą informację na wysokość, waga, kolor itp Tylko drzewa splay są wolne od takich dodatkowych informacji. Ale większość ludzi boi się drzew splay, ze względu na ramdomness ich struktury!

Wreszcie drzewa mogą również zawierać informacje masy w węzłach, umożliwiając zrównoważenie ciężaru. Różne systemy mogą być stosowane. Należy zrównoważyć gdy poddrzewo zawiera więcej niż 3 razy liczbę elementów pozostałych poddrzewie. Zrównoważenie ponownie zrobić albo throuh pojedynczej lub podwójnej rotacji. Oznacza to najgorszy przypadek 2.4logn. Można uciec z 2 razy zamiast 3, znacznie lepszej proporcji, ale może to oznaczać, pozostawiając trochę mniej Thant 1% poddrzew niezrównoważony tu i tam. Zdradliwy!

Jaki rodzaj drzewa jest najlepszy? AVL na pewno. Są to najprostsze do kodu i mają najbliższy logN ich najgorszy wysokość. Dla drewna 1000000 elementów AVL będzie wynosić co najwyżej wysokości 29, RB 40 i ciężar wynosi 36 lub 50, w zależności od stosunku.

Istnieje wiele innych zmiennych: przypadkowość, stosunek dodaje, usuwa wyszukiwania itp

Odpowiedział 16/07/2011 o 02:52
źródło użytkownik

głosy
36

To naprawdę zależy od zastosowania. Drzewo AVL zwykle ma więcej obroty równoważeniu. Więc jeśli aplikacja nie ma zbyt wielu operacji wstawiania i usuwania, ale ciężary mocno na poszukiwania, a następnie Drzewo AVL prawdopodobnie jest dobrym wyborem.

std::map wykorzystuje drzewo czerwono-czarne, jak robi rozsądny kompromis między szybkością węzła wstawiania / usuwania oraz poszukiwania.

Odpowiedział 26/05/2012 o 19:32
źródło użytkownik

głosy
2

Aktualizować 14.06.2017: webbertiger edytować swoją odpowiedź po tym jak skomentował. Należy wskazać, że jego odpowiedź jest teraz dużo lepiej do moich oczu. Ale ciągle moją odpowiedź tak Informacje dodatkowe ...

Ze względu na fakt, że myślę, że pierwsza odpowiedź jest błędna (korekta: nie zarówno już), a trzeci ma złą afirmacji. Czuję, że miał na celu wyjaśnienie rzeczy ...

W 2 najbardziej popularne są drzewa AVL i Red Black (RB). Różnica głównym leżą w utylizacji:

  • AVL: Lepiej, jeśli stosunek konsultacji (odczyt) jest większy niż manipulacji (modyfikacja). drukuj stóp pamięć jest trochę mniej niż RB (z powodu kawałka wymaganej do barwienia).
  • RB: Lepiej w ogólnych przypadkach, gdy istnieje równowaga pomiędzy konsultacji (odczyt) i manipulacji (modyfikacja) lub więcej modyfikacji na konsultacji. Nieco większe zużycie pamięci z powodu przechowywania czerwono-czarne flagi.

Główną różnicą pochodzą z farbowania. Trzeba mniej działań re-balance w RB drzewa niż AVL bo kolorystyka pozwalają czasami pominąć lub skrócić działań re-balance, które mają względny koszt cześć. Ze względu na barwy, RB drzewa mają także wyższy poziom węzłów, ponieważ może to zaakceptować czerwonych węzłów między czarnych (o możliwościach ~ 2x więcej poziomów) dokonujących wyszukiwania (odczyt) trochę mniej wydajne ... ale ponieważ jest to stałej (2x), to pozostanie w O (log n).

Jeśli wziąć pod uwagę spadek wydajności o zmianę drzewa (significative) vs trafień wydajności konsultacji z drzewa (prawie nieznaczne), to stają się naturalną wolą RB nad AVL o ogólnym przypadku.

Odpowiedział 30/05/2017 o 20:33
źródło użytkownik

głosy
5

Dotychczasowe odpowiedzi zająć tylko alternatywy drzewa i czerwone czarny prawdopodobnie pozostanie tylko ze względów historycznych.

Dlaczego nie stolik hash?

W drzewie rodzaj wymaga tylko częściowego uporządkowania (<porównanie), który będzie używany jako klucz w mapie. Jednak tabele hash wymagają, aby każdy typ klucz posiada funkcję skrótu zdefiniowany. Utrzymanie tych wymagań typu do minimum jest bardzo ważne dla programowania generycznego.

Projektując dobry stolik hash wymaga gruntownej wiedzy o kontekście, który będzie używany. Należy używać otwartego adresowania, lub połączoną łańcuchowym? Jakie poziomy obciążenia należy przyjąć przed zmiana rozmiaru? Należy używać drogiego hash który unika kolizji, lub taki, który jest szorstki i szybko?

(C ++ 11 nie dodać tabele mieszania z unordered_map. Można zobaczyć z dokumentacją to wymaga przestawienia polityki skonfigurować wiele z tych opcji).

Ponieważ STL nie jest w stanie przewidzieć, co jest najlepszym wyborem dla aplikacji, domyślnie musi być bardziej elastyczny. Drzewa „po prostu działa” i skalować ładnie.

Co z innymi drzewami?

Drzewo czerwono-czarne jest oferta szybko odnośnika i samodzielnego bilansowania przeciwieństwie BSTS. Inny użytkownik wskazał swoje zalety nad samobalansującego Drzewo AVL.

Alexander Stepanov (Twórca STL) powiedział, że będzie korzystać z B * drzewo zamiast drzewo czerwono-czarne, jeśli pisał std::mapponownie. To dlatego, że węzły mogą przechowywać dowolną liczbę elementów zwarty który jest bardziej przyjazny dla nowoczesnych pamięci podręcznej pamięci.

Jedną z największych zmian od tego czasu wzrost skrytek. chybienia pamięci podręcznej są bardzo kosztowne, więc lokalizacja odniesienia jest znacznie ważniejsze. struktury danych węzła oparte, które mają niską lokalizację odniesienia, uczynić znacznie mniej sensu. Gdybym projektowaniu STL dzisiaj, chciałbym mieć inny zestaw pojemników. Na przykład w pamięci B * -tree jest znacznie lepszym wyborem niż drzewo czerwono-czarne wdrażania asocjacyjną kontenera. - Alexander Stepanov

Więcej można przeczytać tutaj

Czy drzewo czerwono-czarne lub B * zawsze najlepszy?

Przy innych okazjach Alex stwierdził, że std::vectorjest prawie zawsze najlepszym lista pojemnik z podobnych powodów. To rzadko ma sens używania std::listlub std::dequenawet dla tych sytuacjach, uczono nas w szkole (takie jak usunięcie elementu ze środka listy). std::vectorto tak szybko, że bije te struktury za wszystko, ale dużych n.

Stosując to samo rozumowanie, jeśli masz tylko niewielką liczbę elementów (setek?) Z zastosowaniem std::vectori przeszukiwania liniowego mogą być bardziej efektywne niż realizacja drzewa std::map. W zależności od częstotliwości wprowadzania, posortowaną std::vectorpołączeniu z std::binary_searchmoże być najszybszy wybór.

Odpowiedział 22/12/2017 o 00:46
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more