Wykład Drzewa zbalansowane AVL i -3-4
Drzewa AVL Wprowadzenie Drzewa AVL Definicja drzewa AVL Operacje wstawiania i usuwania Złożoność obliczeniowa Drzewa -3-4 Definicja drzewa -3-4 Operacje wstawiania i usuwania Złożoność obliczeniowa Literatura R. Sedgewick, Algorytmy w C++, rozdz. 3
Wprowadzenie Drzewa BST są wygodne do efektywnego implementowania operacji: Search, Successor, Predecessor, Minimum, Maximum, Insert, Delete w czasie O(h), (gdzie h jest wysokością drzewa) Jeśli drzewo jest zbalansowane (ma wtedy wysokość h = O(lg n)), operacje te są najbardziej efektywne. Operacje wstawiania i usuwania elementów mogą powodować, że drzewo przestaje być zbalansowane. W najgorszym przypadku drzewo staje się listą liniową (h = O(n))! 3
Drzewa zbalansowane Staramy się znaleźć takie metody operowania na drzewie, żeby pozostawało ono zbalansowane. Jeżeli operacja Insert lub Delete spowoduje utratę zbalansowania drzewa, będziemy przywracać tę własność w czasie co najwyżej O(lgn) tak aby nie zwiększać złożoności. Potrzebujemy zapamiętywać dodatkowe informacje, aby to osiągnąć. Najbardziej popularne struktury danych dla drzew zbalansowanych to: Drzewa AVL: różnica wysokości dla poddrzew wynosi co najwyżej Drzewa -3-4 drzewa zbalansowane, ale nie binarne Drzewa czerwono-czarne: o wysokości co najwyżej (lg n + ) 4
Drzewa AVL Definicja: drzewem AVL nazywamy drzewo BST, takie że dla każdego z węzłów różnica wysokości jego lewego i prawego poddrzewa wynosi co najwyżej. Skrót AVL pochodzi od nazwisk twórców: Adelson-Velskii oraz Landis h x h- Sh- S h- h- S h S h = S h + S h 5
Przykład drzewa AVL 4 44 7 78 3 50 48 6 3 88 6
Wysokość drzewa AVL Twierdzenie:wysokość drzewa AVL n() 3 przechowującego n węzłów wynosi O(log n). 4 n() Dowód: ograniczymy najpierw n(h): minimalną ilość wewnętrznych węzłów w drzewie AVL o wysokości h. widać, że n() = i n() = dla n >, drzewo o wysokości h zawiera korzeń oraz dwa poddrzewa o wysokościach h- i h-. stąd: n(h) = + n(h-) + n(h-) wiemy, że n(h-) > n(h-), więc n(h) > n(h-). Dalej n(h) > n(h-), n(h) > 4n(h-4), n(h) > 8n(n-6),,n(h) > i n(h-i) rozwiązując powyższe dostaniemy n(h) > h/-, czyli h < log n(h) + Stąd wysokość drzewa AVL wynosi O(log n) 7
Wstawianie Wstawiamy tak jak do drzewa BST Zawsze dodajemy nowy liść. Przykład : 44 44 7 78 7 78 a=y c=z 3 50 88 3 50 88 48 6 48 6 b=x w 54 przed po wstawieniu 54 8
Przebudowa drzewa niech (a,b,c) będzie pożądaną listą wierzchołków w porządku inorder Przeprowadzamy rotacje, niezbędne do przemieszczenia b na górę poddrzewa a=z b=y (pozostałe dwa przypadki są symetryczne) a=z c=y przypadek : podwójna rotacja (prawa c, a potem lewa a) T 0 T 0 c=x b=x T b=y T 3 b=x T T 3 a=z c=x T T a=z c=y przypadek : pojedyncza Rotacja (lewa rotacja a) T 0 T T T 3 T 0 T T T 3 9
Rotacje (przypomnienie) Rotacja w prawo y x x δ Rotacja w lewo α y α β β δ α x β i x y δ α x y i β y δ 0
Przykład: Left-Rotate () 7 4 x 3 6 9 8 y 4 9 7 0
Przykład: Left-Rotate () 7 4 x 3 6 α 9 4 8 9 y 7 β 0 δ
Przykład: Left-Rotate (3) 7 4 8 y 3 6 x 9 9 α 4 7 β 0 δ 3
Przykład (wstawiamy element 54) 44 4 7 78 3 3 50 88 48 6 5 44 7 78 3 y 3 50 4 x 48 3 6 z 5 6 4 7 88 54 T 3 T 0 T T 4
Przykład (po wstawieniu 54) niezbalansowane... 5 44 7 78 3 y 3 50 4 x 48 3 6 54 T T 0 T 7...zbalansowane z 5 6 4 7 88 T 3 4 44 3 y 6 3 50 3 78 5 48 54 4 x T z 6 7 88 T 0 T T 3 5
Przebudowa drzewa (pojedyncza rotacja przyp. ) a = z b = y c = x rotacja a = z b = y c = x T 0 T T T 3 T 0 T T T 3 a = x b = y c = z rotacja a = x b = y c = z T 0 T T T 3 T 3 T T T 0 6
Przebudowa drzewa (podwójna rotacja przyp. ) a = z b = x c = y rotacje a = z b = x c = y T 0 T T T 3 T 0 T T T 3 a = y b = x c = z rotacje a = y b = x c = z T 0 T 3 T T 3 T T 0 T T 7
Usuwanie z drzewa AVL Usuwamy, jak z drzewa BST może spowodować to zaburzenie zbalansowania drzewa. Przykład: 44 44 7 6 7 6 3 50 78 50 78 48 54 88 48 54 88 Przed usunięciem 3 Po usunięciu 8
Przywracanie zbalansowania po usunięciu Niech z będzie pierwszym niezbalansowanym węzłem, na który natrafiamy idąc od w. Niech y będzie dzieckiem z o większej wysokości, a x jego dzieckiem o większej wysokości. Przeprowadzamy przebudowę drzewa w x, tak aby przywrócić zbalansowanie w z (węzły a,b,c mają być w porządku inorder). Ponieważ operacja taka może zachwiać balans w węźle powyżej - musimy sprawdzać zbalansowanie drzewa powyżej (aż do korzenia) a=z 44 6 w 7 6 b=y 44 78 50 78 c=x 7 50 88 48 54 88 48 54 9
Złożoność obliczeniowa operacji na drzewach AVL Pojedyncza przebudowa zabiera czas O() Jeśli korzystamy ze struktury drzewa binarnego (tylko lub rotacje) Wyszukiwanie zajmuje O(log n) Wysokość drzewa wynosi O(log n), nie potrzeba przebudowywać drzewa Wstawianie zajmuje O(log n) Odnalezienie miejsca O(log n) Przebudowa drzewa O(log n) ze względu na wysokość drzewa Usuwanie - O(log n) Odnalezienie zabiera czas O(log n) Naprawa drzewa O(log n) ze względu na wysokość drzewa 0
Drzewa -3-4 9 5 7 0 4
Drzewa poszukiwań o wielu drogach Drzewem poszukiwań o wielu drogach (B-drzewem) nazywamy uporządkowane drzewo o następujących cechach: Każdy węzeł wewnętrzny posiada co najmniej potomków i przechowuje d elementów-kluczy (k i, o i ), gdzie d jest ilością potomków węzła Dla każdego węzła o potomkach v v v d przechowującego klucze k k k d Klucze w poddrzewie v są mniejsze od k Klucze w poddrzewie v i są pomiędzy k i i k i (i =,, d ) Klucze w poddrzewie v d są większe od k d Liście nie przechowują kluczy 4 6 8 5 7 3 30
Przechodzenie InOrder w drzewach o wielu drogach Możliwe jest rozszerzenie notacji odwiedzania węzłów InOrder z drzew binarnych na drzewa o wielu drogach Odwiedzamy element (k i, o i ) w węźle v pomiędzy rekursywnymi odwiedzinami poddrzew v o korzeniu w v i i v i + Odwiedzane węzły w tak zdefiniowanym porządku InOrder są uporządkowane rosnąco 4 8 6 8 5 7 3 4 6 0 4 8 3 5 7 9 3 6 9 30 5 7 3
Poszukiwanie w drzewach o wielu drogach Podobnie do poszukiwania w drzewie BST Dla każdego węzła wewnętrznego o potomkach v v v d o kluczach k k k d : k = k i (i =,, d ):poszukiwanie zakończone sukcesem k < k : poszukiwanie kontynuujemy w poddrzewie v k i < k < k i (i =,, d ): poszukiwanie kontynuujemy w poddrzewie v i k > k d : poszukiwania kontynuujemy w poddrzewie v d Dotarcie do liścia kończy poszukiwania (porażka) Przykład : odszukujemy klucza 30 4 6 8 5 7 3 30 4
Drzewa -3-4 Drzewa -3-4 nazywane też (,4) są drzewami poszukiwań o wielu drogach o następujących własnościach własność ilości potomków: każdy węzeł wewnętrzny ma co najwyżej 4 potomków własność wysokości: wszystkie liście mają tę samą wysokość W zależności od ilości potomków, wewnętrzne węzły będziemy nazywać -węzłami, 3-węzłami i 4-węzłami 0 5 4 8 8 7 3 5
Wysokość w drzewach -3-4 Twierdzenie: Drzewo -3-4 przechowujące n elementów ma wysokość O(log n) dowód: niech h będzie wysokością drzewa -3-4 o n elementach ponieważ mamy co najmniej i elementów na poziomie i = 0,, h i nie ma elementów ma poziomie h, więc n + + 4 + + h = h stąd, h log (n + ) Wyszukiwanie w drzewie -3-4 o n elementach zajmuje czas O(log n) poziom 0 h h elementy h 0 6
Wstawianie Nowy element (k, o) wstawiamy do węzła v ostatniego wewnętrznego węzła, przez który przechodziliśmy poszukując k Nie psujemy własności wysokości drzewa Możemy spowodować przepełnienie węzła (v może stać się 5-węzłem) Przykład: wstawianie 30 powoduje przepełnienie 0 5 4 8 8 v 7 3 35 0 5 4 8 8 7 30 3 35 v 7
Przepełnienie i rozdzielanie węzła Problem przepełnienia można rozwiązać przez podział węzła v: niech v v 5 będą potomkami v i k k 4 będą kluczami w v węzeł v zastępujemy węzłami v' i v" v' jest 3-węzłem o kluczach k k i potomkach v v v 3 v" jest -węzłem o kluczach k 4 i potomkach v 4 v 5 klucz k 3 jest wstawiany do rodzica u węzła v (to może tworzyć nowy korzeń) Przepełnienie może teraz nastąpić w węźle u u 5 4 8 7 30 3 35 v u 5 4 3 8 7 30 v' 35 v" v v v 3 v 4 v 5 v v v 3 v 4 v 5 8
Analiza wstawiania Algorytm insertitem(k, o). Odszukujemy klucz k w celu zlokalizowania węzła do wstawienia wartości v. Dodajemy nowy element (k, o) w węźle v 3. while overflow(v) if isroot(v) twórz nowy pusty korzeń nad v v split(v) Niech T będzie drzewem -3-4 o n elementach T ma wysokość O(log n) krok zajmuje czas O(log n), ponieważ odwiedzamy O(log n) węzłów krok zajmuje czas O() krok 3 zabiera O(log n) czasu, ponieważ każde rozdzielanie zabiera O() i możemy mieć O(log n) takich operacji Stąd wstawianie do drzewa -3-4 zajmuje czas O(log n) 9
Usuwanie Rozważania na temat usuwania można sprowadzić tylko do przypadku usuwania wartości z węzła posiadającego jedynie potomków liście W przeciwnym razie (węzły wewnętrzne) zastępujemy element kolejnym w porządku inorder (następnikiem jego lewe dziecko musi być liściem) Przykład: usuwanie 4 zastępujemy 4 przez następnik w porządku inorder - 7 0 5 4 8 8 7 3 35 0 5 7 8 8 3 35 30
Niedobór i łączenie Usunięcie elementu z węzła v może spowodować niedobór - v może stać się -węzłem (0 klucz, potomek) Dla obsługi tej sytuacji należy połączyć v z rodzicem u, rozpatrzmy dwa przypadki przypadek : sąsiedni brat v jest -węzłem operacja łączenia: łączymy v z bratem w i przenosimy element z u do połączonego węzła v' po połączeniu, niedobór może nastąpić w węźle powyżej (u) u 9 4 u 9 5 7 0 w v 5 7 0 4 v' 3
Niedobór i łączenie przypadek : sąsiedni brat w węzła v jest 3-węzłem lub 4-węzłem przenosimy:. potomka w do v. element z u do v 3. element z w do u po przeniesieniu nie występują przepełnienia u 4 9 u 4 8 6 8 w v w 6 9 v 3
Analiza usuwania Niech T będzie drzewem -3-4 o n elementach wysokość T wynosi O(log n) Operacja usuwania: odwiedzamy O(log n) węzłów aby odszukać węzeł, z którego usuwamy element obsługa niedoborów może prowadzić do wykonania serii O(log n) łączeń węzłów (przyp. ) oraz jednego przesuwania (przyp. ) każde łączenie zajmuje O() Stąd operacja usuwania w drzewie -3-4 zajmuje czas O(log n) 33