|
Serwis Edukacyjny w I-LO w Tarnowie
Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
Drzewa czerwono-czarne (ang. red-black trees) są odmianą samoorganizujących się binarnych drzew poszukiwań, którą wynalazł niemiecki informatyk Rudolf Bayer w roku 1972 i którą następnie opisali w 1978 Leonidas J. Guibas i Robert Sedgewick. W liściach drzew czerwono-czarnych nie przechowuje się danych. Liście te nawet nie muszą znajdować się bezpośrednio w pamięci komputera. Puste wskazanie w polu syna węzła może być interpretowane jako liść. Jednakże używanie rzeczywistych liści upraszcza niektóre algorytmy na drzewach czerwono-czarnych. W celu zaoszczędzenia pamięci często wybiera się pojedynczy węzeł-strażnika (ang. sentinel node), który pełni rolę wszystkich liści w drzewie. W takim przypadku węzły wewnętrzne w drzewie czerwono-czarnym w polach synów-liści przechowują wskazania do tego węzła strażnika. Puste drzewo zawiera jedynie węzeł strażnika.
Drzewa czerwono-czarne gwarantują, iż ich wysokość nie przekroczy dwukrotnej wartości wysokości minimalnej. Dokonywane jest to przez kolorowanie węzłów na czerwono lub czarno i stosowanie po każdej operacji wstawiania lub usuwania odpowiedniej procedury równoważącej drzewo, tak aby były spełnione następujące warunki:

Pascaltype
PRBTnode = ^RBTnode;
RBTnode = record
up : PBSTnode;
left : PBSTnode;
right : PBSTnode;
key : integer;
color : char;
Data: typ_danych;
end; |
struct RBTnode
{
RBTnode * up;
RBTnode * left;
RBTnode * right;
int key;
char color;
typ_danych data;
}; |
BasicType RBTnode up As RBTnode Ptr left As RBTnode Ptr right As RBTnode Ptr key As Integer color As String * 1 data As typ_danych End Type |
| Python (dodatek) |
class RBTnode:
def __init__(self, k, c, d):
self.up = None
self.left = None
self.right = None
self.key = k
self.color = c
self.data = d
|
color = "B" : węzeł czarny, BLACK color = "R" : węzeł czerwony, RED
Operacja wstawiania węzła do drzewa czerwono-czarnego składa się z następujących etapów:


Przypadek 1:
Wujek C (brat ojca B, czyli drugi syn węzła A) wstawionego węzła X jest czerwony.

Przypadek 2:
Wujek C jest czarny, a węzeł X jest prawym synem węzła B (przypadek lustrzany: wujek B jest czarny, a X jest lewym synem węzła C).

Przypadek 3:
Wujek C jest czarny, a węzeł X jest lewym synem węzła B (przypadek lustrzany: wujek B jest czarny, a X jest prawym synem węzła C):


K01: Utwórz nowy węzeł K02: X ← adres nowego węzła K03: X→left ← S ; liśćmi staje się węzeł strażnik K04: X→right ← S K05: X→up ← root K06: X→key ← k K07: Jeśli X→up ≠ S, ; sprawdzamy, czy drzewo jest puste to idź do kroku K10 K08: root ← X ; jeśli tak, to nowy węzeł staje się ; jego korzeniem K09: Idź do K17 ; przechodzimy do sprawdzania warunków ; drzewa czerwono-czarnego K10: Jeśli k < X→up→key, ; porównujemy klucze to idź do kroku K14 K11: Jeśli X→up→right = S, ; jeśli prawy syn nie istnieje to: X→up→right ← X ; (jest nim strażnik), to nowy ; węzeł staje się prawym synem i idź do kroku K17 ; i przechodzimy do sprawdzania ; warunków drzewa czerwono-czarnego K12: X→up ← X→up→right ; inaczej przechodzimy do prawego syna K13: Idź do kroku K10 ; i kontynuujemy pętlę K14: Jeśli X→up→left = S, ; to samo dla lewego syna to: X→up→left ← X i idź do kroku K17 K15: X→up ← X→up→left K16: Idź do kroku K10 K17: X→color ← RED ; węzeł kolorujemy na czerwono K18: Dopóki X ≠ rootX→up→color = RED , wykonuj kroki K19..K47 ; w pętli sprawdzamy kolejne przypadki K19: Jeśli X→up ≠ X→up→up→left, to idź do kroku K34 ; skok do przypadków lustrzanych K20: Y ← X→up→up→right ; Y wskazuje wujka węzła X K21: Jeśli Y→color = BLACK , ; sprawdzamy przypadek nr 1 to idź do kroku K27 ; - wujek jest czerwony K22: X→up→color ← BLACK ; ojca kolorujemy na czarno K23: Y→color ← BLACK ; wujka kolorujemy na czarno K24: X→up→up→color ← RED ; dziadka kolorujemy na czerwono K25: X ← X→up→up ; za nowe X przyjmujemy dziadka K26: Następny obieg pętli K18 ; i kontynuujemy pętlę K27: Jeśli X ≠ X→up→right, ; sprawdzamy przypadek 2 to idź do kroku K30 ; - wujek czarny, X prawy syn K28: X ← X→up ; X staje się swoim ojcem K29: rot_l(root, X) ; wykonujemy rotację w lewo, ; X przechodzi do lewego syna K30: X→up→color ← BLACK ; przypadek 3 ; - wujek czarny, X lewy syn K31: X→up→up→color ← RED ; zmieniamy kolory ojca i dziadka K32: rot_r(root, X→up→up) ; wykonujemy rotację w prawo ; względem dziadka K33: Idź do kroku K48 ; i wychodzimy z pętli K34: Y ← X→up→up→left ; przypadki lustrzane K35: Jeśli Y→color = BLACK , to idź do kroku K41 K36: X→up→color ← BLACK K37: Y→color ← BLACK K38: X→up→up→color ← RED K39: X ← X→up→up K40: Następny obieg pętli K18 K41: Jeśli X ≠ X→up→left, to idź do kroku K44 K42: X ← X→up K43: rot_r(root, X) K44: X→up→color ← BLACK K45: X→up→up→color ← RED K46: rot_l(root, X→up→up) K47: Idź do kroku K48 ; wychodzimy z pętli K18 K48: root→color ← BLACK ; kolorujemy korzeń na czarno K49: Zakończ
Usuwanie węzła z drzewa czerwono-czarnego jest nieco trudniejsze od wstawiania, ponieważ należy rozpatrzyć więcej różnych przypadków. Operację wykonujemy dwuetapowo. Najpierw usuwamy z drzewa wybrany węzeł tak, jak dla drzew BST. Mamy tutaj cztery możliwe przypadki:
| Przypadek 1. Usuwany węzeł X nie posiada lewego syna (jest nim węzeł strażnik). Usuwamy z drzewa węzeł X, a na jego miejsce wstawiamy prawego syna Y. Jeśli usunięty węzeł był czarny, to operacja ta może naruszać warunek 4, jeśli Y oraz jego nowy ojciec są węzłami czerwonymi. W takim przypadku przywracamy warunek zmieniając kolor węzła Y na czarny. |
![]() |
| Przypadek 2. Usuwany węzeł X nie posiada prawego syna. Jest to przypadek symetryczny do przypadku 1. Usuwamy węzeł X, zastępując go lewym synem. Jeśli X był czarny, kolorujemy Y na czarno. Zwróć uwagę, że przypadki 1 i 2 również obejmują brak synów w węźle X. W takim przypadku X zostaje zastąpiony przez węzeł strażnika, który jest czarny. |
![]() |
| Przypadek 3. Węzeł X posiada dwóch synów, z których prawy Z jest następnikiem. Węzeł X zastępujemy następnikiem Z. Lewym synem Z staje się węzeł Y. Następnik zawsze ma lewego syna pustego (w przeciwnym razie nie byłby najmniejszym elementem w prawej gałęzi drzewa). Następnik otrzymuje kolor węzła X. Jeśli następnik był czarny, to jego prawy syn ZR otrzymuje umownie dodatkowy kolor czarny – jeśli ZR był czarny, to jest teraz podwójnie czarny, a jeśli był czerwony, to jest czerwono-czarny. Zostanie to rozwiązane w dalszej części algorytmu. |
![]() |
| Przypadek 4. Węzeł X posiada dwóch synów, jednak następnik nie jest jego prawym synem. Następnik A zostaje zastąpiony w drzewie swoim prawym synem B (kolor A zachowujemy dla B). Do węzła X kopiujemy zawartość następnika A bez pola koloru (kolor X zostaje zachowany dla A). Jeśli następnik A był czarny, to jego prawy syn B otrzymuje umownie dodatkowy kolor czarny – jeśli B był czarny, to jest teraz podwójnie czarny, a jeśli był czerwony, to jest czerwono-czarny. Zostanie to rozwiązane w dalszej części algorytmu. |
![]() |
Przypadki 3 i 4 wymagają korekty drzewa, jeśli następnik był czarny (w przeciwnym razie drzewo wciąż jest drzewem czerwono-czarnym i operację usuwania węzła możemy zakończyć). W takim przypadku prawy syn następnika posiada dodatkowy kolor czarny. Kolor ten dodajemy umownie po to, aby był wciąż spełniony warunek nr 5. Ponieważ ze ścieżek, które wcześniej zawierały usunięty węzeł, zniknął jeden węzeł czarny, to musimy ten kolor dodać do węzła znajdującego się na tych ścieżkach, czyli do prawego syna następnika. Powstaje ciąg czterech symetrycznych przypadków, które są lustrzanymi odbiciami. Umówmy się, że węzeł posiadający dodatkowy kolor czarny będziemy oznaczali gwiazdką. Kolor szary oznacza, że węzeł może być czerwony lub czarny.
| Przypadek 1. Brat węzła A* (węzeł C) jest czerwony. Wykonujemy rotację w lewo względem B (ojciec węzła A*). Zamieniamy kolory ojca (węzeł B) i dziadka (węzeł C). W ten sposób brat A* (teraz węzeł D) staje się węzłem czarnym. Otrzymujemy jeden z przypadków 2, 3 lub 4, które rozróżniamy po kolorach synów brata A*. |
![]() |
| Przypadek 2. Brat węzła A* (węzeł C) jest czarny i posiada czarnych synów (węzły D i E). Zabieramy jeden kolor czarny z węzłów A i C, przenosząc go w górę do węzła B. W efekcie węzeł A nie ma już nadmiarowego koloru czarnego, staje się normalnym węzłem czerwonym lub czarnym. Z kolei zabranie koloru czarnego z węzła C skutkuje zmianą koloru na czerwony. Ponieważ obaj synowie D i E są czarni, zmiana ta nie powoduje naruszenia warunku drzewa czerwono-czarnego. Ponieważ problem dodatkowego koloru czarnego przeniósł się w górę drzewa do węzła B (ojca A), to wracamy do rozpatrywania przypadków z nowym węzłem A*, który teraz jest ojcem poprzedniego węzła A, czyli węzłem B*. |
![]() |
| Przypadek 3. Brat węzła A* (węzeł C) jest czarny, lewy syn węzła C jest czerwony, prawy syn węzła C jest czarny. Wykonujemy rotację w prawo względem węzła C, po czym zamieniamy kolory pomiędzy węzłami C i D. Otrzymujemy w ten sposób przypadek 4. |
![]() |
| Przypadek 4. Brat węzła A* (węzeł C) jest czarny, a jego prawy syn jest czerwony. Wykonujemy rotację względem węzła B (ojciec A*). Przenosimy kolor z węzła B do C. W takim przypadku B traci kolor i możemy w tym węźle umieścić dodatkowy kolor czarny z węzła A. Dzięki temu pozbywamy się dodatkowej czerni. Na koniec węzeł E kolorujemy na czarno. Ta transformacja przywraca strukturę drzewa czerwono-czarnego, zatem kończy operację usuwania węzła. |
![]() |
K01: Jeśli (X→left = S)(X→right = S), to Y ← X ; Y jest usuwanym węzłem, jest to albo X, inaczej Y ← succ_rbt(X) ; albo jego następnik K02: Jeśli Y→left ≠ S, to Z ← Y→left ; Z jest lewym lub Inaczej Z ← Y→right ; prawym synem usuwanego elementu K03: Z→up ← Y→up ; Rodzicem Z będzie ojciec Y K04: Jeśli Y→up ≠ S, ; Sprawdzamy, czy usuwany to idź do kroku K07 ; węzeł jest korzeniem K05: root ← Z ; Jeśli tak, to nowym korzeniem ; będzie jego syn K06: Idź do kroku K08 ; Przechodzimy do poprawiania ; struktury drzewa K07: Jeśli Y = Y→up→left, ; Z zastępuje Y w strukturze drzewa to Y→up→left ← Z inaczej Y→up→right ← Z K08: Jeśli Y ≠ X, ; Jeśli X nie jest usuwanym węzłem, to X→key ← Y→key ; to przenosimy klucze z Y do X K09: Jeśli Y→color = RED , ; Jeśli usuwany węzeł jestczerwony, to idź do kroku K52 ; to kończymy K10: Dopóki Z ≠ root
(Z→color = BLACK ): wykonuj kroki K11…K51 ; Dokonujemy poprawy struktury ; drzewa czerwono-czarnego K11: Jeśli Z = Z→up→right, ; Skok do przypadków lustrzanych to idź do kroku K33 K12: W ← Z→up→right ; W wskazuje brata Z K13: Jeśli W→color = BLACK , to idź do kroku K18 K14: W→color ← BLACK ; Przypadek 1 K15: Z→up→color ← RED K16: rot_l(root, Z→up) K17: W ← Z→up→right K18: Jeśli (W→left→color = RED )
(W→right→color = RED ), to idź do kroku K22 K19: W→color ← RED ; Przypadek 2 K20: Z ← Z→up K21: Następny obieg pętli K10 K22: Jeśli W→right→color = RED , to idź do kroku K27 K23: W→left→color ← BLACK ; Przypadek 3 K24: W→color ← RED K25: rot_r(root, W) K26: W ← Z→up→right K27: W→color ← Z→up→color ; Przypadek 4 K28: Z→up→color ← BLACK K29: W→right→color ← BLACK K30: rot_l(root, Z→up) K31; Z ← root ; Z = root spowoduje przerwanie pętli i następny obieg pętli K10 K32: W ← Z→up→left ; Przypadki lustrzane K33: Jeśli W→color = BLACK , to idź do kroku K38 K34: W→color ← BLACK ; Przypadek 1 K35: Z→up→color ← RED K36: rot_r(root, Z→up) K37: W ← Z→up→left K38: Jeśli (W→left→color = RED )
(W→right→color = RED ), to idź do kroku K42 K39: W→color ← RED ; Przypadek 2 K40: Z ← Z→up K41: Następny obieg pętli K10 K42: Jeśli W→left→color = RED , to idź do kroku K47 K43: W→right→color ← BLACK ; Przypadek 3 K44: W→color ← RED K45: rot_l(root, W) K46: W ← Z→up→left K47: W→color ← Z→up→color ; Przypadek 4 K48: Z→up→color ← BLACK K49: W→left→color ← BLACK K50: rot_r(root, Z→up) K51: Z ← root ; Z = root spowoduje przerwanie pętli i następny obieg pętli K10 K52: Z→color ← BLACK ; węzeł Z kolorujemy na czarno K53: Usuń Y K54: Zakończ
|
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
| Program tworzy drzewo czerwono-czarne z 30 kluczy o wartościach od 1 do 30. Węzły z tymi kluczami będą wstawiane losowo. Po utworzeniu drzewa zostaje ono wyświetlona. Następnie program wylosuje połowę kluczy i usunie węzły z tymi kluczami z drzewa. Drzewo końcowe również zostanie wyświetlone. |
Pascal// Drzewo czerwono-czarne
// Data: 11.06.2013
// (C)2013 mgr Jerzy Wałaszek
//---------------------------
program RedBlackTree;
// Liczba węzłów
const MAXN = 30;
// Typ węzłów drzewa RBT
type
PRBTnode = ^RBTnode;
RBTnode = record
up, left, right : PRBTnode;
key : integer;
color : char;
end;
// Definicja typu obiektowego RBtree
RBtree = object
private
// Węzeł strażnika
S : RBTnode;
// Korzeń drzewa czerwono-czarnego
root : PRBTnode;
// Łańcuchy do znaków ramek
cr, cl, cp : string;
// Wypisuje rekurencyjnie drzewo
procedure t_print_rbt(sp, sn : string;
p : PRBTnode);
// Usuwa rekurencyjnie drzewo
procedure dfs_release(p : PRBTnode);
// Rotacja w lewo względem A
procedure rot_l(A : PRBTnode);
// Rotacja w prawo względem A
procedure rot_r(A : PRBTnode);
// Wyszukuje najmniejszy węzeł w p
function min_rbt(p : PRBTnode) : PRBTnode;
// Wyszukuje następnik p
function succ_rbt(p : PRBTnode) : PRBTnode;
public
constructor init;
destructor destroy;
// Wypisuje drzewo
procedure print_rbt();
// Wyszukuje węzeł o kluczu k
function find_rbt(k : integer) : PRBTnode;
// Wstawia węzeł o kluczu k
procedure insert_rbt(k : integer);
// Usuwa węzeł X
procedure remove_rbt(X : PRBTnode);
end;
// Konstruktor drzewa
//-------------------
constructor RBtree.init;
begin
// Inicjujemy łańcuchy do ramek
cr := #218#196;
cl := #192#196;
cp := #179#32;
// Inicjujemy strażnika
S.color := 'B';
S.up := @S;
S.left := @S;
S.right := @S;
// Korzeń wskazuje strażnika
root := @S;
end;
// Destruktor drzewa
//------------------
destructor RBtree.destroy;
begin
// Rekurencyjnie usuwamy węzły
dfs_release(root);
end;
// Usuwa rekurencyjnie
// drzewo czerwono-czarne
//-----------------------
procedure RBtree.dfs_release(p : PRBTnode);
begin
if p <> @S then
begin
// usuwamy lewe poddrzewo
dfs_release(p^.left);
// usuwamy prawe poddrzewo
dfs_release(p^.right);
// usuwamy sam węzeł
dispose(p);
end;
end;
// Wypisuje zawartość drzewa
//--------------------------
procedure RBtree.t_print_rbt(sp, sn : string;
p : PRBTnode);
var
t : string;
i : integer;
begin
if p <> @S then
begin
t := sp;
if sn = cr then
t[length(t)-1] := ' ';
t_print_rbt(t+cp, cr, p^.right);
t := Copy(sp, 1, length(sp)-2);
for i := 1 to length(t) do
write(char(ord(t[i])));
for i := 1 to length(sn) do
write(char(ord(sn[i])));
writeln(p^.color, ':', p^.key);
t := sp;
if sn = cl then
t[length(t)-1] := ' ';
t_print_rbt(t+cp, cl, p^.left);
end;
end;
// Wypisuje zawartość drzewa
//--------------------------
procedure RBtree.print_rbt();
begin
t_print_rbt ('', '', root);
end;
// Wyszukuje węzeł o kluczu k
// Jeśli węzeł nie zostanie
// znaleziony, to zwraca
// wskazanie puste nil
//---------------------------
function RBtree.find_rbt(k : integer)
: PRBTnode;
var
p : PRBTnode;
begin
p := root;
while(p <> @S) and (p^.key <> k) do
if k < p^.key then p := p^.left
else p := p^.right;
if p = @S then find_rbt := nil
else find_rbt := p;
end;
// Wyszukuje najmniejszy węzeł
// w poddrzewie o korzeniu p
//----------------------------
function RBtree.min_rbt(p : PRBTnode)
: PRBTnode;
begin
if p <> @S then
while p^.left <> @S do
p := p^.left;
min_rbt := p;
end;
// Zwraca następnik p
//-------------------
function RBtree.succ_rbt(p : PRBTnode)
: PRBTnode;
var
r : PRBTnode;
begin
succ_rbt := @S;
if p <> @S then
begin
if p^.right <> @S then
succ_rbt := min_rbt(p^.right)
else
begin
r := p^.up;
while(r <> @S) and (p = r^.right) do
begin
p := r;
r := r^.up;
end;
succ_rbt := r;
end;
end;
end;
// Wykonuje rotację w lewo względem A
//-----------------------------------
procedure RBtree.rot_l(A : PRBTnode);
var
B, p : PRBTnode;
begin
B := A^.right;
if B <> @S then
begin
p := A^.up;
A^.right := B^.left;
if A^.right <> @S then
A^.right^.up := A;
B^.left := A;
B^.up := p;
A^.up := B;
if p <> @S then
begin
if p^.left = A then
p^.left := B
else
p^.right := B;
end
else root := B;
end;
end;
// Wykonuje rotację w prawo względem A
//------------------------------------
procedure RBtree.rot_r(A : PRBTnode);
var
B, p : PRBTnode;
begin
B := A^.left;
if B <> @S then
begin
p := A^.up;
A^.left := B^.right;
if A^.left <> @S then
A^.left^.up := A;
B^.right := A;
B^.up := p;
A^.up := B;
if p <> @S then
begin
if p^.left = A then
p^.left := B
else
p^.right := B;
end
else root := B;
end;
end;
// Wstawia do drzewa
// węzeł o kluczu k
//------------------
procedure RBtree.insert_rbt(k : integer);
var
X, Y : PRBTnode;
begin
// Tworzymy nowy węzeł
new(X);
// Inicjujemy pola
X^.left := @S;
X^.right := @S;
X^.up := root;
X^.key := k;
if X^.up = @S then
// X staje się korzeniem
root := X
else
// Szukamy liścia
// do zastąpienia przez X
while true do
begin
if k < X^.up^.key then
begin
if X^.up^.left = @S then
begin
// X zastępuje lewy liść
X^.up^.left := X;
break;
end;
X^.up := X^.up^.left;
end
else
begin
if X^.up^.right = @S then
begin
// X zastępuje prawy liść
X^.up^.right := X;
break;
end;
X^.up := X^.up^.right;
end;
end;
// Węzeł kolorujemy na czerwono
X^.color := 'R';
while(X <> root) and (X^.up^.color = 'R') do
begin
if X^.up = X^.up^.up^.left then
begin
// Y -> wujek X
Y := X^.up^.up^.right;
// Przypadek 1
if Y^.color = 'R' then
begin
X^.up^.color := 'B';
Y^.color := 'B';
X^.up^.up^.color := 'R';
X := X^.up^.up;
continue;
end;
// Przypadek 2
if X = X^.up^.right then
begin
X := X^.up;
rot_l(X);
end;
// Przypadek 3
X^.up^.color := 'B';
X^.up^.up^.color := 'R';
rot_r(X^.up^.up);
break;
end
else
// Przypadki lustrzane
begin
Y := X^.up^.up^.left;
// Przypadek 1
if Y^.color = 'R' then
begin
X^.up^.color := 'B';
Y^.color := 'B';
X^.up^.up^.color := 'R';
X := X^.up^.up;
continue;
end;
// Przypadek 2
if X = X^.up^.left then
begin
X := X^.up;
rot_r(X);
end;
// Przypadek 3
X^.up^.color := 'B';
X^.up^.up^.color := 'R';
rot_l(X^.up^.up);
break;
end;
end;
root^.color := 'B';
end;
// Usuwa z drzewa węzeł X
//-----------------------
procedure RBtree.remove_rbt(X : PRBTnode);
var
W, Y, Z : PRBTnode;
begin
if(X^.left = @S) or
(X^.right = @S) then
Y := X
else
Y := succ_rbt(X);
if Y^.left <> @S then
Z := Y^.left
else
Z := Y^.right;
Z^.up := Y^.up;
if Y^.up = @S then
root := Z
else
if Y = Y^.up^.left then
Y^.up^.left := Z
else
Y^.up^.right := Z;
if Y <> X then X^.key := Y^.key;
// Naprawa struktury
// drzewa czerwono-czarnego
if Y^.color = 'B' then
while(Z <> root) and (Z^.color = 'B') do
if Z = Z^.up^.left then
begin
W := Z^.up^.right;
// Przypadek 1
if W^.color = 'R' then
begin
W^.color := 'B';
Z^.up^.color := 'R';
rot_l(Z^.up);
W := Z^.up^.right;
end;
// Przypadek 2
if(W^.left^.color = 'B') and
(W^.right^.color = 'B') then
begin
W^.color := 'R';
Z := Z^.up;
continue;
end;
// Przypadek 3
if W^.right^.color = 'B' then
begin
W^.left^.color := 'B';
W^.color := 'R';
rot_r(W);
W := Z^.up^.right;
end;
// Przypadek 4
W^.color := Z^.up^.color;
Z^.up^.color := 'B';
W^.right^.color := 'B';
rot_l(Z^.up);
// To spowoduje zakończenie pętli
Z := root;
end
else
// Przypadki lustrzane
begin
W := Z^.up^.left;
// Przypadek 1
if W^.color = 'R' then
begin
W^.color := 'B';
Z^.up^.color := 'R';
rot_r(Z^.up);
W := Z^.up^.left;
end;
if(W^.left^.color = 'B') and
(W^.right^.color = 'B') then
// Przypadek 2
begin
W^.color := 'R';
Z := Z^.up;
continue;
end;
if W^.left^.color = 'B' then
// Przypadek 3
begin
W^.right^.color := 'B';
W^.color := 'R';
rot_l(W);
W := Z^.up^.left;
end;
// Przypadek 4
W^.color := Z^.up^.color;
Z^.up^.color := 'B';
W^.left^.color := 'B';
rot_r(Z^.up);
// To spowoduje zakończenie pętli
Z := root;
end;
Z^.color := 'B';
dispose(Y);
end;
//**********************
//*** PROGRAM GŁÓWNY ***
//**********************
var
// Tablica kluczy węzłów
Tk : array [0..MAXN-1] of integer;
i, x, i1, i2 : integer;
// Obiekt drzewa czerwono-czarnego
RB : RBtree;
begin
randomize;
// Tworzymy puste drzewo
RB.init;
// Tablicę wypełniamy wartościami kluczy
for i := 0 to MAXN-1 do
Tk[i] := i+1;
// Mieszamy tablicę
for i := 1 to 300 do
begin
// Losujemy 2 indeksy
i1 := random(MAXN);
i2 := random(MAXN);
// Wymieniamy Tk[i1] <--> Tk[i2]
x := Tk[i1];
Tk[i1] := Tk[i2];
Tk[i2] := x;
end;
// Na podstawie tablicy tworzymy
// drzewo czerwono-czarne
for i := 0 to MAXN-1 do
begin
write(Tk[i], ' ');
RB.insert_rbt(Tk[i]);
end;
writeln; writeln;
// Wyświetlamy zawartość drzewa
RB.print_rbt();
writeln; writeln;
// Ponownie mieszamy tablicę
for i := 1 to 300 do
begin
i1 := random(MAXN);
i2 := random(MAXN);
x := Tk[i1];
Tk[i1] := Tk[i2];
Tk[i2] := x;
end;
// Usuwamy połowę węzłów
for i := 0 to MAXN div 2 do
begin
write(Tk[i], ' ');
RB.remove_rbt(RB.find_rbt(Tk[i]));
end;
writeln; writeln;
// Wyświetlamy zawartość drzewa
RB.print_rbt();
// Usuwamy drzewo z pamięci
RB.destroy;
end.
|
// Drzewo czerwono-czarne
// Data: 11.06.2013
// (C)2013 mgr Jerzy Wałaszek
//------------------------------
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
// Liczba węzłów
const int MAXN = 30;
// Typ węzłów drzewa RBT
struct RBTnode
{
RBTnode * up;
RBTnode * left;
RBTnode * right;
int key;
char color;
};
// Definicja typu obiektowego RBtree
class RBtree
{
private:
// Węzeł strażnika
RBTnode S;
// Korzeń drzewa czerwono-czarnego
RBTnode * root;
// Łańcuchy do znaków ramek
string cr, cl, cp;
// Wypisuje rekurencyjnie drzewo
void t_print_rbt(string sp,
string sn,
RBTnode * p);
// Usuwa rekurencyjnie drzewo
void dfs_release(RBTnode * p);
// Rotacja w lewo względem A
void rot_l(RBTnode * A);
// Rotacja w prawo względem A
void rot_r(RBTnode * A);
// Wyszukuje najmniejszy węzeł w p
RBTnode * min_rbt(RBTnode * p);
// Wyszukuje następnik p
RBTnode * succ_rbt(RBTnode * p);
public:
// Konstruktor klasy
RBtree();
// Destruktor klasy
~RBtree();
// Wypisuje drzewo
void print_rbt();
// Wyszukuje węzeł o kluczu k
RBTnode * find_rbt(int k);
// Wstawia węzeł o kluczu k
void insert_rbt(int k);
// Usuwa węzeł X
void remove_rbt(RBTnode * X);
};
// Konstruktor drzewa
//-------------------
RBtree::RBtree()
{
cr = cl = cp = " ";
cr[0] = 218; cr[1] = 196;
cl[0] = 192; cl[1] = 196;
cp[0] = 179;
// Inicjujemy strażnika
S.color = 'B';
S.up = &S;
S.left = &S;
S.right = &S;
// Korzeń wskazuje strażnika
root = &S;
}
// Destruktor drzewa
//------------------
RBtree::~RBtree()
{
// Rekurencyjnie usuwamy węzły
dfs_release(root);
}
// Usuwa rekurencyjnie
// drzewo czerwono-czarne
//-----------------------
void RBtree::dfs_release(RBTnode * p)
{
if(p != &S)
{
// usuwamy lewe poddrzewo
dfs_release(p->left);
// usuwamy prawe poddrzewo
dfs_release(p->right);
// usuwamy sam węzeł
delete p;
}
}
// Wypisuje zawartość drzewa
//--------------------------
void RBtree::t_print_rbt(string sp,
string sn,
RBTnode * p)
{
string t;
if(p != &S)
{
t = sp;
if(sn == cr) t[t.length()-2] = ' ';
t_print_rbt(t+cp, cr, p->right);
t = t.substr(0, sp.length()-2);
cout << t << sn
<< p->color << ":" << p->key
<< endl;
t = sp;
if(sn == cl) t[t.length()-2] = ' ';
t_print_rbt(t+cp, cl, p->left);
}
}
// Wypisuje zawartość drzewa
//--------------------------
void RBtree::print_rbt()
{
t_print_rbt("", "", root);
}
// Wyszukuje węzeł o kluczu k
// Jeśli węzeł nie zostanie
// znaleziony, to zwraca
// wskazanie puste NULL
//---------------------------
RBTnode * RBtree::find_rbt(int k)
{
RBTnode * p;
p = root;
while((p != &S) && (p->key != k))
if(k < p->key) p = p->left;
else p = p->right;
if(p == &S) return NULL;
return p;
}
// Wyszukuje najmniejszy
// węzeł w poddrzewie
// o korzeniu p
//----------------------
RBTnode * RBtree::min_rbt(RBTnode * p)
{
if(p != &S)
while(p->left != &S) p = p->left;
return p;
}
// Zwraca następnik p
//-------------------
RBTnode * RBtree::succ_rbt(RBTnode * p)
{
RBTnode * r;
if(p != &S)
{
if(p->right != &S)
return min_rbt(p->right);
else
{
r = p->up;
while((r != &S) && (p == r->right))
{
p = r;
r = r->up;
}
return r;
}
}
return &S;
}
// Wykonuje rotację
// w lewo względem A
//------------------
void RBtree::rot_l(RBTnode * A)
{
RBTnode * B, * p;
B = A->right;
if(B != &S)
{
p = A->up;
A->right = B->left;
if(A->right != &S)
A->right->up = A;
B->left = A;
B->up = p;
A->up = B;
if(p != &S)
{
if(p->left == A)
p->left = B;
else
p->right = B;
}
else root = B;
}
}
// Wykonuje rotację
// w prawo względem A
//-------------------
void RBtree::rot_r(RBTnode * A)
{
RBTnode * B, * p;
B = A->left;
if(B != &S)
{
p = A->up;
A->left = B->right;
if(A->left != &S)
A->left->up = A;
B->right = A;
B->up = p;
A->up = B;
if(p != &S)
{
if(p->left == A)
p->left = B;
else
p->right = B;
}
else root = B;
}
}
// Wstawia do drzewa
// węzeł o kluczu k
//------------------
void RBtree::insert_rbt(int k)
{
RBTnode * X, * Y;
// Tworzymy nowy węzeł
X = new RBTnode;
// Inicjujemy pola
X->left = &S;
X->right = &S;
X->up = root;
X->key = k;
// X staje się korzeniem
if(X->up == &S)
root = X;
else
// Szukamy liścia
// do zastąpienia przez X
while(true)
{
if(k < X->up->key)
{
if(X->up->left == &S)
{
// X zastępuje lewy liść
X->up->left = X;
break;
}
X->up = X->up->left;
}
else
{
if(X->up->right == &S)
{
// X zastępuje prawy liść
X->up->right = X;
break;
}
X->up = X->up->right;
}
}
// Węzeł kolorujemy na czerwono
X->color = 'R';
while((X != root) && (X->up->color == 'R'))
{
if(X->up == X->up->up->left)
{
// Y -> wujek X
Y = X->up->up->right;
// Przypadek 1
if(Y->color == 'R')
{
X->up->color = 'B';
Y->color = 'B';
X->up->up->color = 'R';
X = X->up->up;
continue;
}
// Przypadek 2
if(X == X->up->right)
{
X = X->up;
rot_l(X);
}
// Przypadek 3
X->up->color = 'B';
X->up->up->color = 'R';
rot_R (X->up->up);
break;
}
else
// Przypadki lustrzane
{
Y = X->up->up->left;
// Przypadek 1
if(Y->color == 'R')
{
X->up->color = 'B';
Y->color = 'B';
X->up->up->color = 'R';
X = X->up->up;
continue;
}
// Przypadek 2
if(X == X->up->left)
{
X = X->up;
rot_R (X);
}
// Przypadek 3
X->up->color = 'B';
X->up->up->color = 'R';
rot_L (X->up->up);
break;
}
}
root->color = 'B';
}
// Usuwa z drzewa węzeł X
//-----------------------
void RBtree::remove_rbt(RBTnode * X)
{
RBTnode * W, * Y, * Z;
if((X->left == &S) || (X->right == &S))
Y = X;
else
Y = succ_rbt(X);
if(Y->left != &S)
Z = Y->left;
else
Z = Y->right;
Z->up = Y->up;
if(Y->up == &S)
root = Z;
else
if(Y == Y->up->left)
Y->up->left = Z;
else
Y->up->right = Z;
if(Y != X)
X->key = Y->key;
// Naprawa struktury
// drzewa czerwono-czarnego
if(Y->color == 'B')
{
while((Z != root) && (Z->color == 'B'))
if(Z == Z->up->left)
{
W = Z->up->right;
if(W->color == 'R')
{
// Przypadek 1
W->color = 'B';
Z->up->color = 'R';
rot_L (Z->up);
W = Z->up->right;
}
if((W->left->color == 'B') &&
(W->right->color == 'B'))
{
// Przypadek 2
W->color = 'R';
Z = Z->up;
continue;
}
if(W->right->color == 'B')
{
// Przypadek 3
W->left->color = 'B';
W->color = 'R';
rot_R (W);
W = Z->up->right;
}
// Przypadek 4
W->color = Z->up->color;
Z->up->color = 'B';
W->right->color = 'B';
rot_L (Z->up);
// To spowoduje zakończenie pętli
Z = root;
}
else
{
// Przypadki lustrzane
W = Z->up->left;
if(W->color == 'R')
{
// Przypadek 1
W->color = 'B';
Z->up->color = 'R';
rot_R (Z->up);
W = Z->up->left;
}
if((W->left->color == 'B') &&
(W->right->color == 'B'))
{
// Przypadek 2
W->color = 'R';
Z = Z->up;
continue;
}
if(W->left->color == 'B')
{
// Przypadek 3
W->right->color = 'B';
W->color = 'R';
rot_L (W);
W = Z->up->left;
}
// Przypadek 4
W->color = Z->up->color;
Z->up->color = 'B';
W->left->color = 'B';
rot_R (Z->up);
// To spowoduje zakończenie pętli
Z = root;
}
}
Z->color = 'B';
delete Y;
}
//**********************
//*** PROGRAM GŁÓWNY ***
//**********************
int main()
{
// Tablica kluczy węzłów
int Tk[MAXN];
int i, i1, i2;
// Obiekt drzewa czerwono-czarnego
RBtree * RB;
srand (time(NULL));
// Tworzymy puste drzewo
RB = new RBtree;
// Tablicę wypełniamy
// wartościami kluczy
for(i = 0; i < MAXN; i++)
Tk[i] = i+1;
// Mieszamy tablicę
for(i = 0; i < 300; i++)
{
// Losujemy 2 indeksy
i1 = rand()%MAXN;
i2 = rand()%MAXN;
// Wymieniamy Tk[i1] <--> Tk[i2]
swap(Tk[i1], Tk[i2]);
}
// Na podstawie tablicy
// tworzymy drzewo czerwono-czarne
for(i = 0; i < MAXN; i++)
{
cout << Tk[i] << " ";
RB->insert_rbt(Tk[i]);
}
cout << endl << endl;
// Wyświetlamy zawartość drzewa
RB->print_rbt();
cout << endl << endl;
// Ponownie mieszamy tablicę
for(i = 0; i < 300; i++)
{
i1 = rand()%MAXN;
i2 = rand()%MAXN;
swap(Tk[i1], Tk[i1]);
}
// Usuwamy połowę węzłów
for(i = 0; i < MAXN >> 1; i++)
{
cout << Tk[i] << " ";
RB->remove_rbt(RB->find_rbt(Tk[i]));
}
cout << endl << endl;
// Wyświetlamy zawartość drzewa
RB->print_rbt();
// Usuwamy drzewo z pamięci
delete RB;
return 0;}
|
Basic' Drzewo czerwono-czarne
' Data: 11.06.2013
' (C)2013 mgr Jerzy Wałaszek
'---------------------------
' Liczba węzłów
const MAXN = 30
' Typ węzłów drzewa RBT
Type RBTnode
up As RBTnode Ptr
left As RBTnode Ptr
right As RBTnode Ptr
key As Integer
color As String * 1
End Type
' Definicja typu obiektowego RBtree
Type RBtree
Private:
' Węzeł strażnika
S As RBTnode
' Korzeń drzewa czerwono-czarnego
root As RBTnode Ptr
' Łańcuchy do znaków ramek
cr As String * 2
cl As String * 2
cp As String * 2
' Usuwa rekurencyjnie drzewo
Declare Sub dfs_release(p As RBTnode Ptr)
' Wypisuje drzewo
Declare Sub t_print_rbt(sp As String, _
sn As String, _
p As RBTnode Ptr)
' Rotacja w lewo względem A
Declare Sub rot_l(A As RBTnode Ptr)
' Rotacja w prawo względem A
Declare Sub rot_r(A As RBTnode Ptr)
' Wyszukuje najmniejszy węzeł w p
Declare Function min_rbt(p As RBTnode Ptr) _
As RBTnode Ptr
' Wyszukuje następnik p
Declare Function succ_rbt (p As RBTnode Ptr) _
As RBTnode Ptr
Public:
' Konstruktor klasy
Declare Constructor()
' Destruktor klasy
Declare Destructor()
' Wypisuje drzewo
Declare Sub print_rbt
' Wyszukuje węzeł o kluczu k
Declare Function find_rbt(k As Integer) _
As RBTnode Ptr
' Wstawia węzeł o kluczu k
Declare Sub insert_rbt(k As Integer)
' Usuwa węzeł X
Declare Sub remove_rbt(X As RBTnode Ptr)
End Type
' Konstruktor drzewa
'-------------------
Constructor RBtree()
cr = Chr(218)+Chr (196)
cl = Chr(192)+Chr (196)
cp = Chr(179)+" "
' Inicjujemy strażnika
S.color = "B"
S.up = @S
S.left = @S
S.right = @S
' Korzeń wskazuje strażnika
root = @S
End Constructor
' Destruktor drzewa
'------------------
Destructor RBtree
' Rekurencyjnie usuwamy węzły
dfs_release root
End Destructor
' Usuwa rekurencyjnie
' drzewo czerwono-czarne
'-----------------------
Sub RBtree.dfs_release(p As RBTnode Ptr)
If p <> @S Then
' usuwamy lewe poddrzewo
dfs_release p->left
' usuwamy prawe poddrzewo
dfs_release p->right
' usuwamy sam węzeł
Delete p
End If
End Sub
' Wypisuje zawartość drzewa
'--------------------------
Sub RBtree.t_print_rbt(sp As String, _
sn As String, _
p As RBTnode Ptr)
Dim As String t
If p <> @S Then
t = sp
If sn = cr Then _
Mid(t, Len(t)-1, 1) = " "
t_print_rbt t+cp, cr, p->right
t = Mid(t, 1, Len(sp)-2)
Print Using "&&&:&";t;sn;p->Color;p->key
t = sp
If sn = cl Then _
Mid(t, Len(t)-1, 1) = " "
t_print_rbt t+cp, cl, p->left
End If
End Sub
' Wypisuje zawartość drzewa
'--------------------------
Sub RBtree.print_rbt
t_print_rbt "", "", root
End Sub
' Wyszukuje węzeł o kluczu k
' Jeśli węzeł nie zostanie
' znaleziony, to zwraca
' wskazanie puste NULL
'---------------------------
Function RBtree.find_rbt(k As Integer) _
As RBTnode Ptr
Dim As RBTnode Ptr p
p = root
while p <> @S AndAlso p->key <> k
If k < p->key Then
p = p->Left
Else
p = p->Right
End If
Wend
If p = @S Then return 0
Return p
End Function
' Wyszukuje najmniejszy
' węzeł w poddrzewie
' o korzeniu p
'----------------------
Function RBtree.min_rbt(p As RBTnode Ptr) _
As RBTnode Ptr
If p <> @S Then _
While p->left <> @S: p = p->Left: Wend
Return p
End Function
' Zwraca następnik p
'-------------------
Function RBtree.succ_rbt(p As RBTnode Ptr) _
As RBTnode Ptr
Dim As RBTnode Ptr r
If p <> @S Then
If p->right <> @S Then
Return min_rbt(p->right)
Else
r = p->up
while r <> @S AndAlso p = r->right
p = r
r = r->up
Wend
Return r
End If
End If
Return @S
End Function
' Wykonuje rotację w lewo względem A
'-----------------------------------
Sub RBtree.rot_l(A As RBTnode Ptr)
Dim As RBTnode Ptr B, p
B = A->Right
If B <> @S Then
p = A->up
A->right = B->Left
If A->right <> @S Then _
A->right->up = A
B->left = A
B->up = p
A->up = B
If p <> @S Then
If p->left = A then
p->left = B
Else
p->right = B
End If
Else
root = B
End If
End If
End Sub
' Wykonuje rotację w prawo względem A
'------------------------------------
Sub RBtree.rot_r(A As RBTnode Ptr)
Dim As RBTnode Ptr B, p
B = A->Left
if B <> @S Then
p = A->up
A->left = B->Right
if A->left <> @S Then _
A->left->up = A
B->right = A
B->up = p
A->up = B
If p <> @S Then
If p->left = A then
p->left = B
Else
p->right = B
End If
Else
root = B
End If
End If
End Sub
' Wstawia do drzewa węzeł o kluczu k
'-----------------------------------
Sub RBtree.insert_rbt(k As Integer)
Dim As RBTnode Ptr X, Y
' Tworzymy nowy węzeł
X = new RBTnode
' Inicjujemy pola
X->left = @S
X->right = @S
X->up = root
X->key = k
If X->up = @S Then
' X staje się korzeniem
root = X
Else
' Szukamy liścia
' do zastąpienia przez X
Do
If k < X->up->key Then
If X->up->left = @S Then
' X zastępuje lewy liść
X->up->left = X
Exit Do
End If
X->up = X->up->Left
Else
If X->up->right = @S Then
' X zastępuje prawy liść
X->up->right = X
Exit Do
End If
X->up = X->up->Right
End If
Loop
End If
' Węzeł kolorujemy na czerwono
X->color = "R"
while X <> root AndAlso X->up->color = "R"
If X->up = X->up->up->Left Then
' Y -> wujek X
Y = X->up->up->Right
If Y->color = "R" Then
' Przypadek 1
X->up->color = "B"
Y->color = "B"
X->up->up->color = "R"
X = X->up->up
Continue While
End If
If X = X->up->Right Then
' Przypadek 2
X = X->up
rot_L X
End If
' Przypadek 3
X->up->color = "B"
X->up->up->color = "R"
rot_R X->up->up
Exit While
Else
' Przypadki lustrzane
Y = X->up->up->Left
if Y->color = "R" Then
' Przypadek 1
X->up->color = "B"
Y->color = "B"
X->up->up->color = "R"
X = X->up->up
Continue While
End If
if X = X->up->Left Then
' Przypadek 2
X = X->up
rot_R X
End If
' Przypadek 3
X->up->color = "B"
X->up->up->color = "R"
rot_L X->up->up
Exit While
End If
Wend
root->color = "B"
End Sub
' Usuwa z drzewa węzeł X
'-----------------------
Sub RBtree.remove_rbt(X As RBTnode Ptr)
Dim As RBTnode Ptr W, Y, Z
If X->left = @S OrElse _
X->right = @S Then
Y = X
Else
Y = succ_rbt(X)
End If
if Y->left <> @S Then
Z = Y->Left
Else
Z = Y->Right
End If
Z->up = Y->up
If Y->up = @S Then
root = Z
ElseIf Y = Y->up->Left Then
Y->up->Left = Z
Else
Y->up->right = Z
End If
If Y <> X Then X->key = Y->key
If Y->color = "B" Then
' Naprawa struktury
' drzewa czerwono-czarnego
While Z <> root AndAlso _
Z->color = "B"
If Z = Z->up->Left Then
W = Z->up->Right
If W->color = "R" Then
' Przypadek 1
W->color = "B"
Z->up->color = "R"
rot_L Z->up
W = Z->up->Right
End If
If W->left->color = "B" AndAlso _
W->right->color = "B" Then
' Przypadek 2
W->color = "R"
Z = Z->up
Continue While
End If
if W->right->color = "B" Then
' Przypadek 3
W->left->color = "B"
W->color = "R"
rot_R W
W = Z->up->Right
End If
' Przypadek 4
W->color = Z->up->Color
Z->up->color = "B"
W->right->color = "B"
rot_L Z->up
' To spowoduje zakończenie pętli
Z = root
Else
' Przypadki lustrzane
W = Z->up->Left
If W->color = "R" Then
' Przypadek 1
W->color = "B"
Z->up->color = "R"
rot_R Z->up
W = Z->up->Left
End If
If W->left->color = "B" AndAlso _
W->right->color = "B" Then
' Przypadek 2
W->color = "R"
Z = Z->up
Continue While
End If
If W->left->color = "B" Then
' Przypadek 3
W->right->color = "B"
W->color = "R"
rot_L W
W = Z->up->Left
End If
' Przypadek 4
W->color = Z->up->Color
Z->up->color = "B"
W->left->color = "B"
rot_R Z->up
' To spowoduje zakończenie pętli
Z = root
End If
Wend
End If
Z->color = "B"
Delete Y
End Sub
'**********************
'*** PROGRAM GŁÓWNY ***
'**********************
' Tablica kluczy węzłów
Dim As Integer Tk(MAXN-1)
Dim As Integer i, i1, i2
' Obiekt drzewa czerwono-czarnego
Dim As RBtree Ptr RB
Randomize
' Tworzymy puste drzewo
RB = new RBtree
' Tablicę wypełniamy wartościami kluczy
For i = 0 To MAXN-1
Tk(i) = i+1
Next
' Mieszamy tablicę
For i = 0 To 300
' Losujemy 2 indeksy
i1 = Int(Rnd()*MAXN)
i2 = Int(Rnd()*MAXN)
' Wymieniamy Tk(i1) <--> Tk(i2)
Swap Tk(i1), Tk(i2)
Next
' Na podstawie tablicy tworzymy
' drzewo czerwono-czarne
For i = 0 To MAXN-1
Print Tk(i);
RB->insert_rbt Tk(i)
Next
Print: Print
' Wyświetlamy zawartość drzewa
RB->print_rbt
Print: Print
' Ponownie mieszamy tablicę
For i = 0 To 300
i1 = Int(Rnd()*MAXN)
i2 = Int(Rnd()*MAXN)
Swap Tk(i1), Tk(i2)
Next
' Usuwamy połowę węzłów
For i = 0 To MAXN\2
Print Tk(i);
RB->remove_rbt RB->find_rbt(Tk(i))
Next
Print: Print
' Wyświetlamy zawartość drzewa
RB->print_rbt
' Usuwamy drzewo z pamięci
Delete RB
End
|
| Python (dodatek) |
# Drzewo czerwono-czarne
# Data: 6.08.2024
# (C)2024 mgr Jerzy Wałaszek
# ------------------------------
import random
# Liczba węzłów
MAXN = 30
# klasa węzłów drzewa
class RBTnode:
def __init__(self, k, c):
self.up = None
self.left = None
self.right = None
self.key = k
self.color = c
# klasa drzewa czerwono-czarnego
class RBtree:
# Konstruktor
def __init__(self):
# Łańcuchy do znaków ramek
self.cr = "┌─"
self.cl = "└─"
self.cp = "│ "
# Inicjujemy strażnika
self.s = RBTnode(0, 'B')
self.s.up = self.s
self.s.left = self.s
self.s.right = self.s
# Korzeń wskazuje strażnika
self.root = self.s
# Usuwa rekurencyjnie drzewo
def dfs_release(self, p):
if p is not self.s:
# usuwamy lewe poddrzewo
self.dfs_release(p.left)
# usuwamy prawe poddrzewo
self.dfs_release(p.right)
# usuwamy wskazania
p.left = None
p.right = None
# wypisuje drzewo
def t_print_bt(self, sp, sn, p):
if p is not self.s:
t = sp
if sn == self.cr:
t = t[:-2] + ' ' + t[-1]
self.t_print_bt(t + self.cp, self.cr, p.right)
t = t[:-2]
print(t, sn, p.color, ":", p.key, sep="")
t = sp
if sn == self.cl:
t = t[:-2] + ' ' + t[-1]
self.t_print_bt(t + self.cp, self.cl, p.left)
# Wypisuje zawartość drzewa
def print_rbt(self):
self.t_print_bt('', '', self.root)
# wyszukuje węzeł o kluczu k
# jeśli węzeł nie zostanie
# znaleziony, to zwraca
# wskazanie puste None
def find_rbt(self, k):
p = self.root
while p is not self.s and \
p.key != k:
if k < p.key:
p = p.left
else:
p = p.right
if p is self.s:
return None
return p
# wyszukuje najmniejszy
# węzeł w poddrzewie
# o korzeniu p
def min_rbt(self, p):
if p is not self.s:
while p.left is not self.s:
p = p.left
return p
# zwraca następnik p
def succ_rbt(self, p):
if p is not self.s:
if p.right is not self.s:
return self.min_rbt(p.right)
else:
r = p.up
while r is not self.s and \
p == r.right:
p = r
r = r.up
return r
return self.s
# wykonuje rotację w lewo względem A
def rot_l(self, a):
b = a.right
if b is not self.s:
p = a.up
a.right = b.left
if a.right is not self.s:
a.right.up = a
b.left = a
b.up = p
a.up = b
if p is not self.s:
if p.left is a:
p.left = b
else:
p.right = b
else:
self.root = b
# wykonuje rotację w prawo względem A
def rot_r(self, a):
b = a.left
if b is not self.s:
p = a.up
a.left = b.right
if a.left is not self.s:
a.left.up = a
b.right = a
b.up = p
a.up = b
if p is not self.s:
if p.left is a:
p.left = b
else:
p.right = b
else:
self.root = b
# wstawia węzeł o kluczu k
def insert_rbt(self, k):
# Tworzymy nowy węzeł
x = RBTnode(k, "")
# Inicjujemy pola
x.left = self.s
x.right = self.s
x.up = self.root
if x.up is self.s:
# X staje się korzeniem
self.root = x
else:
# szukamy liścia
# do zastąpienia przez X
while True:
if k < x.up.key:
if x.up.left is self.s:
# X zastępuje lewy liść
x.up.left = x
break
x.up = x.up.left
else:
if x.up.right is self.s:
# X zastępuje prawy liść
x.up.right = x
break
x.up = x.up.right
# węzeł kolorujemy na czerwono
x.color = "R"
while x is not self.root and \
x.up.color == "R":
if x.up is x.up.up.left:
# Y -> wujek X
y = x.up.up.right
if y.color == "R":
# Przypadek 1
x.up.color = "B"
y.color = "B"
x.up.up.color = "R"
x = x.up.up
continue
if x is x.up.right:
# Przypadek 2
x = x.up
self.rot_l(x)
# Przypadek 3
x.up.color = "B"
x.up.up.color = "R"
self.rot_r(x.up.up)
break
else:
# Przypadki lustrzane
y = x.up.up.left
if y.color == "R":
# Przypadek 1
x.up.color = "B"
y.color = "B"
x.up.up.color = "R"
x = x.up.up
continue
if x is x.up.left:
# Przypadek 2
x = x.up
self.rot_r(x)
# Przypadek 3
x.up.color = "B"
x.up.up.color = "R"
self.rot_l(x.up.up)
break
self.root.color = "B"
# usuwa węzeł X
def remove_rbt(self, x):
if x.left is self.s or \
x.right is self.s:
y = x
else:
y = self.succ_rbt(x)
if y.left is not self.s:
z = y.left
else:
z = y.right
z.up = y.up
if y.up is self.s:
self.root = z
elif y is y.up.left:
y.up.left = z
else:
y.up.right = z
if y is not x:
x.key = y.key
if y.color == "B":
# Naprawa struktury
# drzewa czerwono-czarnego
while z is not self.root and \
z.color == "B":
if z is z.up.left:
w = z.up.right
if w.color == "R":
# Przypadek 1
w.color = "B"
z.up.color = "R"
self.rot_l(z.up)
w = z.up.right
if w.left.color == "B" and \
w.right.color == "B":
# Przypadek 2
w.color = "R"
z = z.up
continue
if w.right.color == "B":
# Przypadek 3
w.left.color = "B"
w.color = "R"
self.rot_r(w)
w = z.up.right
# Przypadek 4
w.color = z.up.color
z.up.color = "B"
w.right.color = "B"
self.rot_l(z.up)
# To spowoduje zakończenie pętli
z = self.root
else:
# Przypadki lustrzane
w = z.up.left
if w.color == "R":
# Przypadek 1
w.color = "B"
z.up.color = "R"
self.rot_r(z.up)
w = z.up.left
if w.left.color == "B" and \
w.right.color == "B":
# Przypadek 2
w.color = "R"
z = z.up
continue
if w.left.color == "B":
# Przypadek 3
w.right.color = "B"
w.color = "R"
self.rot_l(w)
w = z.up.left
# Przypadek 4
w.color = z.up.color
z.up.color = "B"
w.left.color = "B"
self.rot_r(z.up)
# To spowoduje zakończenie pętli
z = self.root
z.color = "B"
# **********************
# *** PROGRAM GŁÓWNY ***
# **********************
# Obiekt drzewa czerwono-czarnego
rb = RBtree()
# Tablicę wypełniamy wartościami kluczy
tk = [i+1 for i in range(MAXN)]
# Mieszamy tablicę
for i in range(300):
# Losujemy 2 indeksy
i1 = random.randrange(MAXN)
i2 = random.randrange(MAXN)
# Wymieniamy tk[i1] <--> tk[i2]
tk[i1], tk[i2] = tk[i2], tk[i1]
# Na podstawie tablicy tworzymy
# drzewo czerwono-czarne
for i in range(MAXN):
print(tk[i], end=" ")
rb.insert_rbt(tk[i])
print()
print()
# Wyświetlamy zawartość drzewa
rb.print_rbt()
print()
print()
# Ponownie mieszamy tablicę
for i in range(300):
i1 = random.randrange(MAXN)
i2 = random.randrange(MAXN)
tk[i1], tk[i2] = tk[i2], tk[i1]
# Usuwamy połowę węzłów
for i in range(MAXN // 2):
print(tk[i], end=" ")
rb.remove_rbt(rb.find_rbt(tk[i]))
print()
print()
# Wyświetlamy zawartość drzewa
rb.print_rbt()
|
| Wynik: |
15 7 24 25 16 1 6 2 21 10 18 17 26 29 13 5 14 12 19 28 30 22 11 20 8 23 9 3 27 4
┌─B:30
┌─R:29
│ └─B:28
│ └─R:27
┌─B:26
│ └─B:25
┌─R:24
│ │ ┌─R:23
│ │ ┌─B:22
│ │ ┌─R:21
│ │ │ │ ┌─R:20
│ │ │ └─B:19
│ └─B:18
│ │ ┌─R:17
│ └─B:16
B:15
│ ┌─B:14
│ ┌─B:13
│ │ └─B:12
│ │ └─R:11
└─R:10
│ ┌─R:9
│ ┌─B:8
│ │ └─R:7
└─B:6
│ ┌─R:5
│ ┌─B:4
│ │ └─R:3
└─R:2
└─B:1
2 26 13 29 15 28 25 1 27 4 3 14 8 7 11 10
┌─B:30
┌─B:24
│ │ ┌─R:23
│ └─B:22
┌─R:21
│ │ ┌─R:20
│ │ ┌─B:19
│ └─B:18
│ └─B:17
B:16
│ ┌─B:12
│ │ └─R:9
└─B:6
└─B:5
|
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.