Algorytmy i struktury danych Struktury danych - drzewa IS/IO, WIMiIP Danuta Szeliga AGH Kraków
Drzewo Drzewo (tree) Drzewo jest hierarchiczną strukturą danych. Def. Drzewo jest to zbiór T jednego lub więcej elementów zwanych węzłami, takich że istnieje jeden wyróżniony węzeł zwany korzeniem drzewa i pozostałe węzły (z wyłączeniem korzenia) są podzielone na m 0 rozłącznych zbiorów T 1,..., T m, z których każdy jest drzewem, zwanym poddrzewem korzenia. Pierwszy obiekt zwany jest korzeniem, kolejne obiekty traktowane są jako jego potomstwo: węzły. Liście to węzły nie mające potomstwa Droga w drzewie sekwencja węzłów w drzewie odpowiadających przejściu w kierunku od korzenia do liścia Pojęcia: rodzic, przodek, potomek, rodzeństwo (dwa węzły są rodzeństwem, gdy mają tego samego ojca) Warianty: drzewa AVL, drzewa czerwono-czarne, BST,...
Drzewa binarne Drzewo binarne jest skończonym zbiorem węzłów, który jest albo pusty, albo zawiera korzeń oraz dwa drzewa binarne Każdy węzeł przechowuje dwa wskaźniki: do lewego poddrzewa left i prawego poddrzewa right root jest wskaźnikiem do drzewa Jeśli root = Λ - drzewo puste wpp root jest adresem korzenia drzewa, left(root) wskazuje lewe poddrzewo, right(root) wskazuje prawe poddrzewo Implementacja wskaźnikowa struct NODE{ T val; // wartość NODE* left; // wskaźnik do lewego syna NODE* right; // wskaźnik do prawego syna * root = null; // początkowo drzewo jest puste
Drzewa binarne - operacje Podstawowe operacje dla drzew wyliczenie wszystkich elementów drzewa ("przejście" drzewa) wyszukanie elementu dodanie nowego elementu/poddrzewa w określonym miejscu drzewa usunięcie elementu/poddrzewa
Przechodzenie drzewa binarnego Jest to systematyczne przeglądanie węzłów w taki sposób, ze każdy węzeł jest odwiedzony dokładnie jeden raz Przejście drzewa wyznacza porządek liniowy w drzewie 6 sposób przechodzenia drzewa VLR, LVR, LRV, VRL, RVL, RLV gdzie: Visit = odwiedź węzeł, Left = idź w lewo, Right = idź w prawo W szczególności wyróżnia się trzy pierwsze: VLR pre-order, wzdłużny: korzeń, lewe poddrzewo, prawe poddrzewo LVR in-order, poprzeczny: lewe poddrzewo, korzeń, prawe poddrzewo LRV post-order, wsteczny: lewe poddrzewo, prawe poddrzewo, korzeń preorder ( NODE* root){ if( root) return ; visit( root ->val) if( root ->left) preorder ( root ->left); if( root ->right ); preorder ( root ->right); inorder ( NODE* root){ if( root) return ; if( root ->left) inorder ( root ->left); visit( root ->val); if(root ->right ) inorder ( root ->right); postorder( NODE* root){ if( root) return ; if( root ->left) postorder( root ->left); if(root -> right) postorder( root ->right); visit( root ->val);
Przykład Pre-order: A B D C E G F H I In-order: D B A E G C H F I Post-order: D B G E H I F C A
Porządek in-order - algorytm nierekurencyjny inorder ( NODE* root){ S = Λ; //S - stos p = root; // p - zmienna pomocnicza while (1){ while (p Λ){ push(s,p); p = p->left; if (S=Λ) return ; // koniec algorytmu p = pop(s); visit (p); p = p->right;
Drzewa poszukiwań binarnych - BST Binarne drzewo poszukiwań (Binary search tree) Binarne drzewo poszukiwań to drzewo binarne o następującej własności każdy element binarnego drzewa poszukiwań ma tę własność, że jego lewostronne potomstwo jest mniejsze bądź równe co do wartości od tego elementu, a prawostronne potomstwo jest większe bądź równe (drzewo BST) Własność binarnego drzewa binarnego dla każdego węzła x drzewa zachodzi: x->val x->left->val oraz x->val x->right->val
Implementacja BST Implementacja wskaźnikowa struct BST_N{ T val; // wartość BST_N* left; // wskaźnik do lewego syna BST_N* right; // wskaźnik do prawego syna BST_N* parent ; // opcjonalny wskaźnik do ojca * root = null; // początkowo drzewo jest puste Implementacja tablicowa struct BST_N{ T val; // wartość integer left; // wskaźnik do lewego syna integer right; // wskaźnik do prawego syna integer parent ; // opcjonalny wskaźnik do ojca tree[n]; root = 0; // początkowo drzewo jest puste
Operacje na BST Przechodzenie drzewa Wyszukiwanie węzła o podanym kluczu największego/najmniejszego następnika/poprzednika węzła Wstawianie węzła do drzewa Usuwanie węzła/podrzewa
Przechodzenie BST I Własność BST umożliwia wypisanie wszystkich znajdujących się w nim elementów w uporządkowany sposób Wykorzystujemy algorytm przechodzenia drzewa metodą inorder (przechodzenie poprzeczne) inorder ( BST_N* root){ if( root) stop; if( root ->left) inorder ( root ->left); wypisz ( root ->val); if( root ->right) inorder ( root ->right); Złożoność: O(n), n liczba węzłów drzewa
Przechodzenie BST II Niekiedy procedura przechodzenia drzewa BST nazywana jest "sortowaniem" drzewiastym Algorytm "sortowania" drzewiastego TreeSort (val arr[]){ BST_N * root arr; // przekształć listę inorder (root); wejściową w BST Procedura ta nie zmienia porządku w tablicy, a jedynie wypisuje elementy w sposób uporządkowany
Wyszukiwanie węzła w BST Wersja rekurencyjna BST_N * find( NODE* root, T x) { if ( root) return 0; if ( root ->val = x) return root; if ( root ->val > x) return find( root ->left,x); else return find( root ->right,x); Wersja iteracyjna NODE* find( BST_N* root, T x) { while ( root root ->val x) if( root ->val > x) root = root ->left; else root = root -> right; return root; Złożoność obliczeniowa: O(h), gdzie h jest wysokością drzewa
Wyszukiwanie minimum i maksimum w BST Wyszukiwanie minimum: należy przejść od korzenia do najbardziej lewego liścia BST_N * min( BST_N* root){ while ( root ->left) root = root ->left; return root; Wyszukiwanie maksimum: należy przejść od korzenia do najbardziej prawego liścia BST_N * max( BST_N* root){ while ( root ->right) root = root ->rigth ; return root; Złożoność obliczeniowa: O(h), gdzie h jest wysokością drzewa
Następnik i poprzednik w BST Struktura BST umożliwia wyznaczenie następnika i poprzednika bez konieczności porównywania kluczy Konieczne jest wtedy przechowywanie w każdym węźle wskaźnika do ojca NODE* parent Jeśli wszystkie klucze są różne, to następnikiem węzła x jest węzeł o najmniejszym kluczu większym od x->val poprzednikiem węzła x jest węzeł o największym kluczu mniejszym od x->val
Następnik w BST Następnik: jeżeli jest prawe poddrzewo, to następnikiem węzła x jest najmniejszy element tego poddrzewa jeżeli brak prawego poddrzewa, to następnikiem węzła x jest jego najniższy przodek, którego lewy syn jest przodkiem x Funkcja next BST_N * next( BST_N* x){ if (x->right) // jeżeli jest prawe poddrzewo return min(x->right ); // najmniejszy na prawo BST_N* y = x->parent ; // brak prawego poddrzewa while (y x = y->right){ // cofamy się do góry x = y; y = y->parent ; return y; Złożoność obliczeniowa: O(h), gdzie h jest wysokością drzewa
Poprzednik w BST Poprzednik: jeżeli jest lewe poddrzewo, to następnikiem węzła x jest największy element tego poddrzewa jeżeli brak lewego poddrzewa, to następnikiem węzła x jest jego najniższy przodek, którego prawy syn jest przodkiem x Funkcja prev BST_N * prev( BST_N* x){ if (x->left) // jeżeli jest lewe poddrzewo return max(x->left); // największy na prawo BST_N* y = x->parent ; // brak prawego poddrzewa while (y x = y->left){ // cofamy x = y; y = y->parent ; return y; się do góry Złożoność obliczeniowa: O(h), gdzie h jest wysokością drzewa
Wstawianie węzła w BST insert - BST( BST_N * root, BST_N* x){ if( root) { // jeżeli drzewo było puste root = x; stop; // x->left = x->right = NULL; BST_N* par = 0; BST_N* son = root; while (son){ par = son; if(par ->val > x->val) son = par ->left; else son = par ->right ; x->parent = par; // x->left = x->right = 0; if( par ->val > x->val) par ->left = x; // x - lewym synem else par ->right = x; // x - prawym synem
Usuwanie węzła w BST (3 przypadki)
Usuwanie węzła w BST remove - BST( BST_N* root, BST_N* z){ BST_N* y; if(z->left z->right) y = next(z); // do usunięcia else y = z; BST_N* x; if(y->left) x = y->left; // sprawdzenie, czy y ma lewego syna else x = y->right; if( x) x->parent = y-> parent ; // podpinamy x do ojca y- ka if(y->parent ) { // ojciec y- ka pokaże na x if(y = y->parent ->left) y->parent ->left = x; else y->parent ->right = x; else root = x; // jeżeli z = y jest korzeniem if( y z) // nadpisanie usuniętego z z->val = y->val; delete y; // fizyczne usunięcie węzła Usuwany element musi być zastąpiony przez lub swój następnik (w prawym poddrzewie) swój poprzednik (w lewym poddrzewie)
Inne rodzaje drzew Drzewa BST z powtarzającymi się kluczami Drzewa pozycyjne: porządek leksykograficzny klucz każdego węzła można jednoznacznie wyznaczyć na podstawie ścieżki od korzenia do tego węzła nie ma potrzeby przechowywania klucza w węźle
Drzewa zrównoważone W drzewach BST pesymistyczny koszt operacji dostępu (wyszukanie, wstawienie, usunięcie) jest proporcjonalny do wysokości drzewa - może być zatem liniowy Kształt drzewa (czyli również jego wysokość) zależy od ciągu wykonywanych na nim operacji Potrzebny jest dodatkowy mechanizm, który zapewni zrównoważenie drzewa, tzn. pomimo zmiany struktury drzewa, jego wysokość zawsze pozostaje logarytmiczna względem jego rozmiaru
Drzewa AVL Drzewo AVL (Gieorgij Adelson-Wielskij, Jewgienij Łandis) to drzewo BST spełniające dodatkowo następujący warunek zrównoważenia: w każdym węźle wysokości obu jego poddrzew różnią się co najwyżej o 1 Implementacja: w każdym węźle przechowywany jest dodatkowy atrybut (współczynnik zrównoważenia), przyjmujący wartości: -1 jeśli lewe poddrzewo jest o 1 wyższe niż prawe 0 jeśli oba poddrzewa są takiej samej wysokości +1 jeśli prawe poddrzewo jest o 1 wyższe niż lewe struct AVL_N{ struct BST_N; integer balance ; * root = NULL; // początkowo drzewo jest puste
Operacje na drzewie BST Operacje wyszukiwania są identyczne jak dla drzewa BST Operacje wstawiania i usuwania elementu są bardziej skomplikowane - zazwyczaj konieczna jest wtedy zmiana struktury drzewa tak, aby drzewo nadal pozostało zrównoważone Wstawienie węzłów o kluczach 9 lub 11 nie zmieni zrównoważenia drzewa Wstawienie węzłów o kluczach 1, 3, 5 lub 7 spowoduje konieczność wyważenia drzewa Do zmiany kształtu drzewa, bez zaburzania własności drzewa BST, służą operacje rotacji
Rotacje Rozróżniamy dwa istotne przypadki rotacji dwie operacje rotacji Rotacja pojedyncza (uczestniczą dwa węzły) Rotacja podwójna (uczestniczą trzy węzły)
Rotacja pojedyncza rot1left ( AVL_N* root, AVL_N* x){ AVL_N* y = x->right ; x->balance = y-> balance = 0; x->right = y->left; x->right ->parent = x; y->parent = x-> parent ; if(x->parent = NULL) root = y; else if(x->parent ->left = x) x->parent ->left = y; else x->parent ->right = y; y->left = x; x->parent = y; rot1right( AVL_N* root, AVL_N* y){ AVL_N* x = y->left; x->balance = y-> balance = 0; y->left = x->right ; y->left ->parent = y; x->parent = y-> parent ; if(y->parent = NULL) root = x; else if(y->parent ->left = y) y->parent ->left = x; else y->parent ->right = x; x->right = y; y->parent = x;
Rotacja podwójna rot2left ( AVL_N* root, AVL_N* A){ AVL_N *C=A->right, *B=C->left; A->right=B->left; // beta A->right ->parent =A; // beta C->left=B->right; // gamma C->left ->parent =C; // gamma B->parent =A-> parent ; if(a->parent =NULL) root=b; else if(a->parent ->left=a) A->parent ->left=b; else A->parent -> right=b; B->left=A; B->right =C; A->parent =C-> parent =B; if(b->balance =1){ A->balance =-1; C->balance =0; else { A->balance =0; C-> balance =+1; B->balance =0; rot2right( AVL_N* root, AVL_N* C){ AVL_N *A=C->left, *B=A->right; A->right=B->left; // beta A->right ->parent =A; // beta C->left=B->right ; // gamma C->left ->parent =C; // gamma B->parent =C-> parent ; if(c->parent =NULL) root=b; else if(c->parent ->left=c) C->parent ->left=b; else C->parent -> right=b; B->left=A; B->right =C; A->parent =C-> parent =B; if(b->balance =1){ A->balance =-1; C->balance =0; else { A->balance =0; C->balance =+1; B->balance =0;
Rotacja podwójna rot2left ( AVL_N* root, AVL_N* A){ integer balb = A->right ->left ->balance ; rot1right( root, A-> right); rot1left ( root, A); if( balb = 1){ B->left -> balance = -1; B->right -> balance = 0; else { B->left -> balance = 0; B->right -> balance = +1; B->balance = 0; rot2right( AVL_N* root, AVL_N* C){ integer balb = A->left ->right ->balance ; rot1left ( root, C->left); rot1right( root, C); if( balb = 1){ B->left -> balance = -1; B->right -> balance = 0; else { B->left -> balance = 0; B->right -> balance = +1; B->balance = 0;
Wstawianie węzłów w drzewie AVL Co może się zdarzyć po wstawieniu nowego w ezła do drzewa? (Wstawiamy węzeł do lewego poddrzewa L): jeżeli h(l) = h(r), to po wstawieniu L i P będą poddrzewami o różnej wysokości, ale kryterium wyważenia będzie wciąż spełnione jeżeli h(l) < h(r), to poddrzewa L i P uzyskują tę samą wysokość jeżeli h(l) > h(r), to kryterium wyważenie nie jest spełnione i drzewo musi być przebudowane
Wstawianie węzłów w drzewie AVL Proces wstawiania węzła 1 Schodzimy po ścieżce przeszukiwania drzewa 2 Wstawiamy nowy liść, wyznaczamy współczynnik wyważenia 3 Wracamy w kierunku korzenia, aktualizując współczynniki wyważenia Jeżeli wysokość drzewa nie zmieniła się, to kończymy W przeciwnym razie kontynuujemy marsz w górę drzewa 4 Jeżeli został naruszony warunek zrównoważenia, to przywracamy go za pomocą rotacji
Wstawianie węzłów w drzewie AVL insert - AVL( AVL_N* root, AVL_N* x, integer bal) { if( root){ root = x; root ->balance = 0; bal = 1; // tu + czy - nie ma znaczenia return ; if(x->val < root ->val) { // wstawiamy do lewego poddrzewa insert ( root ->left, x, bal); switch ( root ->balance ) { case 0: if( bal) root ->balance = -1; break ; case 1: if( bal) root ->balance = 0; break ; default : if( bal == -1) rot1right( root ->parent, root); else rot2right( root ->parent, root); root -> balance = 0; else { // wstawiamy do prawego poddrzewa insert ( root ->right, x, bal); switch (root -> balance ) { case 0: if( bal) root ->balance = 1; break ; case -1: if( bal) root ->balance = 0; break ; default : if( bal == -1) rot2left ( root ->parent, root); else rot1left ( root ->parent, root); root -> balance = 0; bal = root ->balance ;
Usuwanie węzłów w drzewie AVL Algorytm usuwania węzła w drzewie AVL bazuje na algorytmie usuwania węzła dla drzewa BST, choć musi być zmodyfikowany skomplikowany Po zastąpieniu usuniętego węzła jego następnikiem Z miejsca, skąd pobrano następnik, należy przejść w stronę korzenia, przywracając zrównoważenie wierzchołków używając rotacji 1 Odtwarzanie może być zatrzymane, jeśli współczynnik wyważenia zostaje zmieniony na -1 lub 1; oznacza to, że wysokość poddrzewa pozostaje niezmieniona 2 Zmiana współczynnika wyważenia na 0 oznacza zmniejszenie wysokości poddrzewa, aktualizowanie współczynników musi być kontynuowane 3 Jeśli współczynnik zostanie zmieniony na -2 lub 2, to wykonywana jest rotacja w celu przywrócenia struktury AVL Tym razem może się zdarzyć, że trzeba będzie dokonywać rotacji na tej drodze, aż do samego korzenia włącznie
Drzewa AVL Nawet w najgorszym przypadku można w drzewie AVL wykonać następujące operacje wyszukiwanie wstawianie węzła usuwanie węezła Drzewa AVL sprawdzają się najlepiej w sytuacjach, gdy najczęstszą operacją jest wyszukiwanie Twierdzenie (Adelson-Wielskij, Łandis) Niezależnie od liczby węzłów, drzewo AVL nie będzie nigdy wyższe o więcej niż 45% od swego dokładnie wyważonego odpowiednika Wysokość drzewa AVL h(n) o n węzłach log(n+1) h(n) 1.4404 log(n+2) 0.328
Drzewa czerwono-czarne Drzewo czerwono-czarne RBT (Rudolf Bayer, 1972) to drzewo BST, w którym: 1 każdy węzeł jest czerwony lub czarny 2 korzeń drzewa jest czarny 3 każdy liść (przyjmuje się, że liśćmi są elementy NIL) jest czarny 4 każdy czerwony węzeł ma czarne dzieci 5 każda prosta ścieżka z ustalonego węzła do liścia (w dół drzewa) ma tyle samo czarnych węzłów (gdyby miała tyle samo zarówno czerwonych, jak i czarnych węzłów, drzewo miałoby wszystkie gałęzie równej długości)
Drzewa czerwono-czarne struct RBT_N { struct BST_N ; string color ; // uwaga: wystarczy jeden dodatkowy bit * root = NULL; // początkowo drzewo jest puste Wartość NIL reprezentuje jeden czarny węzeł-wartownik Istotne informacje zawierają jedynie węzły wewnętrzne drzewa RB
Drzewa czerwono-czarne Liczbę czarnych węzłów na dowolnej ścieżce z węzła x (wykluczając węzeł x) do liścia nazywamy czarną wysokością węzła bh(x) Czarna wysokość drzewa RB to czarna wysokość jego korzenia
Drzewa czerwono-czarne Wysokość RBT o n węzłach wewnętrznych wynosi co najwyżej 2 log(n+1) Dowód Każde poddrzewo o korzeniu x ma co najmniej 2 bh(x) 1 węzłów wewnętrznych 1 jeśli x ma wysokość 0 (jest liściem), to poddrzewo zawiera co najmniej 2 0 1 = 0 węzłów 2 jeśli x ma 2 synów, to czerwony syn ma wysokość bh(x) a czarny bh(x) 1; wysokość syna jest mniejsza niż wysokość x, zatem każde z poddrzew ma co najmniej 2 bh(x) 1 1 węzłów wewnętrznych; stąd poddrzewo o korzeniu x ma co najmniej 2(2 bh(x) 1 1)+1 = 2 bh(x) 1 węzłów wewnętrznych Jeśli h jest wysokością drzewa, to z własności (4) wynika, że co najmniej połowa węzłów na ścieżce korzeń-liść jest czarna czarna wysokość drzewa wynosi co najmniej h/2, a zatem n 2 h/2 1, stąd teza
Drzewa czerwono-czarne. Operacje Operacje wyszukiwania działają w drzewie RBT w czasie O(log n) Przewaga drzew RBT nad drzewami AVL polega na tym, że przywrócenie własności RBT po wstawieniu/usunięciu węzła wymagają co najwyżej dwóch rotacji Operacje wyszukiwania są identyczne jak dla drzewa BST Operacje wstawiania i usuwania elementu są bardziej skomplikowane - zazwyczaj konieczna jest wtedy zmiana struktury drzewa tak, aby drzewo nadal spełniało warunki drzewa RBT Operacje wstawiania i usuwania mają pesymistyczną złożoność obliczeniową O(log n)
Wstawianie węzła do drzewa RBT Wstawiamy węzeł analogicznie jak dla drzewa BST Kolorujemy wstawiony węzeł na czerwono Przekolorowujemy węzły tak, aby przywrócić własność drzewa RBT Rozpatrywane są 3 przypadki. Przypadek 1 odróżniamy od przypadków 2 i 3, rozpatrując kolor brata ojca węzła, który wstawiamy (x)
Wstawianie węzła do drzewa RBT Przypadek 1: brat y ojca x jest czerwony: Węzeł C (równy węzłowi x w nowej iteracji) jest czerwony Węzeł C parent jest niezmieniony Naprawiono zaburzenie własności (4), ale własność (2) może być dalej zaburzona
Wstawianie węzła do drzewa RBT Przypadek 2: brat y ojca x jest czarny i x jest prawym synem sprowadzamy do Przypadku 3 przez lewą rotację - zachowana jest własność (5) Przypadek 3: brat y ojca x jest czarny i x jest lewym synem: α, β, γ mają czarne korzenie - własność (4) δ też ma czarny korzeń (patrz Przypadek 1) Po wykonaniu tego kroku przerywana jest pętla for
Wstawianie węzła do drzewa RBT insert - RBT( RBT_N* root, RBT_N x){ insert -BST(root, x) while (x root and x->parent ->color = Red){ if (x->parent = x->parent ->parent ->left){ y x->parent ->parent ->right if(y->color = Red){ \\ Przypadek 1 x->parent ->color Black y->color Black x->parent -> parent Red x x->parent ->parent else{ if(x = x->parent ->right){ \\ Przypadek 2 x x-> parent rot1left ( root,x) x->parent ->color Black \\ Przypadek 3 x->parent ->parent ->color Red rot1right( root,x->parent - parent ) else { // tak samo jak dla if z zamienionymi rolami " right" i " left" root ->color Black
Usuwanie węzła z drzewa RBT Usuwamy węzeł analogicznie jak dla drzewa BST Przekolorowujemy węzły tak, aby przywrócić własność drzewa RBT Rozpatrujemy 4 przypadki, w każdym z nich usuwany węzeł jest oznaczony jako x Przypadek 1 zachodzi, jeśli węzeł w, brat węzła x, jest czerwony Przypadki 2, 3 i 4 zachodzą, jeśli węzeł w jest czarny i różnią się od siebie tym, jakie kolory mają synowie w
Usuwanie węzła z drzewa RBT Przypadek 1: brat w węzła x jest czerowny Węzeł w musi mieć czarnych synów można zamienić kolory w i x parent i wykonać lewą rotację w x parent Nowy brat węzła x, jeden z synów w, jest teraz czarny udało się sprowadzić przypadek 1 do jednego z przypadków 2,3 lub 4
Usuwanie węzła z drzewa RBT Przypadek 2: węzeł w jest czarny i obaj jego synowie są koloru czarnego w jest czarny usuwamy po jednej "czarnej jednostce" z x oraz w x pozostaje czarny, w staje się czerwony x->parent otrzymuje dodatkową "czarną jednostkę" jeśli Przypadek 2 powstaje z Przypadku 1, to color nowego węzła wskazywanego przez x jest czerwony, a ponieważ x->parent był czerwony, wykonanie pętli while zostaje przerwane
Usuwanie węzła z drzewa RBT Przypadek 3: węzeł w jest czarny, jego prawy syn jest czarny, a lewy syn jest czerwony zamieniamy kolory w o jego lewego syna w->left i wykonujemy prawą rotację dla w nowy brat w węzła x jest teraz czarny, a jego prawy syn czerwony przekształcono Przypadek 3 do Przypadku 4
Usuwanie węzła z drzewa RBT Przypadek 4: brat w węzła x jest czarny, prawy syn węzła w jest czerwony Przekolorowujemy węzły, wykonujemy lewą rotację dla węzła x->parent możliwe stało się usunięcie nadmiarowej "czarnej jednostki" w x Przypisanie zmiennej x wskazania na korzeń drzewa przerywa wykonanie pętli while
Usuwanie węzła z drzewa RBT Procedura zbliżona do procedury usuwania węzła w drzewie BST Przywrócenie własności drzewa RB następuje w procedurze remove-rbt-fixup remove - RBT( RBT_N* root, RBT_N* z){ if(z->left = Λ z->right = Λ) y z else y next(z) if(y->left Λ) x y->left else x y->right x->parent y-> parent if(y->parent = Λ) root x else if(y = y->parent ->left) y->parent ->left x else y->parent ->right x if(y z) z->val y->val if(y->color = Black) remove -RBT -FixUp(root,x) delete y
Usuwanie węzła z drzewa RBT remove -RBT - FixUp( RBT_N* root, RBT_N* x){ while (x root x->color = Black){ if(x = x->parent ->left){ w x->parent ->right if(w->color = Red){ // Przypadek 1 w->color Black x->parent ->color Red rot1left ( root, x->parent ) w x->parent ->right if(w->left ->color = Black w->right ->color = Black){ w->color Red // Przypadek 2 x x-> parent else{ if(w->right -> color = Black){ // Przypadek 3 w->left -> color Black w->color Red rot1right( root, w) w x->parent ->right w->color x->parent ->color // Przypadek 4 x->parent ->color Black w->right ->color Black rot1left ( root, x->parent ) x root else{// tak jak dla if tylko zamień rolami " right" i " left" x->color Black