Serwis Edukacyjny
w I-LO w Tarnowie
obrazek

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

SPIS TREŚCI
Podrozdziały

Wiadomości podstawowe

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:

  1. Każdy węzeł drzewa jest albo czerwony, albo czarny.
  2. Każdy liść drzewa (węzeł pusty nil) jest zawsze czarny.
  3. Korzeń drzewa jest zawsze czarny.
  4. Jeśli węzeł jest czerwony, to obaj jego synowie są czarni – innymi słowy, w drzewie nie mogą występować dwa kolejne czerwone węzły, ojciec i syn.
  5. Każda prosta ścieżka od danego węzła do dowolnego z jego liści potomnych zawiera tę samą liczbę węzłów czarnych.
obrazek
Drzewo czerwono-czarne
Węzeł strażnik jest oznaczony jako czarne koło
Węzły drzew czerwono-czarnych będziemy reprezentować następującą strukturą danych:
Pascal
type
  PRBTnode = ^RBTnode;
  RBTnode  = record
    up    : PBSTnode;
    left  : PBSTnode;
    right : PBSTnode;
    key   : integer;
    color : char;
    Data: typ_danych;
  end;
C++
struct RBTnode
{
  RBTnode * up;
  RBTnode * left;
  RBTnode * right;
  int key;
  char color;
  typ_danych data;
};
Basic
Type 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
Pole color zawiera informację o kolorze węzła:
color = "B" : węzeł czarny,  BLACK 
color = "R" : węzeł czerwony,  RED 
Liście będą reprezentowane przez węzeł strażnika o kolorze czarnym. Węzeł strażnika będzie posiadał wszystkie pola wyzerowane.

do podrozdziału  do strony 

Wstawianie węzła do drzewa czerwono-czarnego

Operacja wstawiania węzła do drzewa czerwono-czarnego składa się z następujących etapów:

Tworzymy nowy węzeł, inicjujemy go danymi, po czym wstawiamy do drzewa czerwono-czarnego za pomocą zwykłej procedury wstawiania węzła do drzewa binarnego (ponieważ drzewo czerwono-czarne wciąż jest drzewem binarnym). Gdy węzeł znajdzie się w drzewie, kolorujemy go na czerwono i sprawdzamy czy nie zostały zaburzone warunki drzewa czerwono-czarnego.
obrazek
Jeśli nowy węzeł jest korzeniem, to zmieniamy jego kolor na czarny (ponieważ korzeń drzewa musi być czarny). Wstawianie jest zakończone. Jeśli ojciec nowego węzła jest czarny, to również kończymy, ponieważ warunki drzewa czerwono-czarnego w takim przypadku nie zostały zaburzone:
obrazek
W przeciwnym razie mamy dwa kolejne węzły czerwone i musimy przywrócić warunki drzewa czerwono-czarnego (zauważ, że czerwony ojciec nowego węzła nie może być korzeniem z uwagi na warunek nr 3: korzeń drzewa musi być czarny). W tym celu rozważamy 3 przypadki, które występują w dwóch lustrzanych postaciach (z zamienionymi stronami: lewa z prawą):

Przypadek 1:

Wujek C (brat ojca B, czyli drugi syn węzła A) wstawionego węzła X jest czerwony.
obrazek
Rodzica B i wujka C kolorujemy na czarno. Dziadka A kolorujemy na czerwono.
obrazek
Jeśli węzeł A jest korzeniem drzewa, to zmieniamy jego kolor na czarny (ponieważ korzeń drzewa musi być czarny) i kończymy. W przeciwnym razie za nowe X przyjmujemy A i sprawdzamy od początku kolejne przypadki na wyższym poziomie drzewa.

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).
obrazek
Wykonujemy rotację w lewo względem węzła B (w przypadku lustrzanym wykonujemy rotację w prawo względem C).
obrazek
Za X przyjmujemy węzeł B i przechodzimy do przypadku 3.

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):
obrazek
Wykonujemy rotację w prawo względem węzła A (w przypadku lustrzanym wykonujemy rotację w lewo względem A):
obrazek
Zmieniamy kolory węzłów AB na przeciwne:
obrazek
Operacja wstawiania zostaje zakończona, ponieważ węzeł B ma taki sam kolor jak poprzednio węzeł A. Zatem operacja rotacji przywróciła strukturę drzewa czerwono-czarnego.

Algorytm wstawiania węzła do drzewa czerwono-czarnego

Wejście:

root : referencja do zmiennej, która przechowuje wskazanie korzenia drzewa czerwono-czarnego.
: klucz nowego węzła (mogą również występować dodatkowe dane, które chcemy przechowywać w węźle).
S : wskazanie węzła strażnika.

Wyjście:

Drzewo czerwono-czarne z wstawionym nowym węzłem.

Elementy pomocnicze:

X : wskazanie nowego węzła.
Y : wskazanie węzła.
rot_l(root, x) : rotacja w lewo względem x.
rot_r(root, x) : rotacja w prawo względem x.

Lista kroków:

K01: Utwórz nowy węzeł
K02: X ← adres nowego węzła
K03: XleftS ; liśćmi staje się węzeł strażnik
K04: XrightS
K05: Xuproot
K06: Xkeyk
K07: Jeśli XupS, ; sprawdzamy, czy drzewo jest puste
     to idź do kroku K10
K08: rootX ; 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 < Xupkey, ; porównujemy klucze
     to idź do kroku K14
K11: Jeśli Xupright = S, ; jeśli prawy syn nie istnieje
     to: XuprightX    ; (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: XupXupright ; inaczej przechodzimy do prawego syna
K13: Idź do kroku K10 ; i kontynuujemy pętlę
K14: Jeśli Xupleft = S, ; to samo dla lewego syna
     to: XupleftX
     i idź do kroku K17
K15: XupXupleft
K16: Idź do kroku K10
K17: Xcolor ←  RED  ; węzeł kolorujemy na czerwono
K18: Dopóki Xroot obrazek Xupcolor =  RED , 
     wykonuj kroki K19..K47 ; w pętli sprawdzamy kolejne przypadki
K19:   Jeśli XupXupupleft, 
       to idź do kroku K34 ; skok do przypadków lustrzanych
K20:   YXupupright ; Y wskazuje wujka węzła X
K21:   Jeśli Ycolor =  BLACK , ; sprawdzamy przypadek nr 1
       to idź do kroku K27        ; - wujek jest czerwony
K22:   Xupcolor BLACK  ; ojca kolorujemy na czarno
K23:   Ycolor BLACK  ; wujka kolorujemy na czarno
K24:   Xupupcolor RED  ; dziadka kolorujemy na czerwono
K25:   XXupup ; za nowe X przyjmujemy dziadka
K26:   Następny obieg pętli K18 ; i kontynuujemy pętlę
K27:   Jeśli XXupright, ; sprawdzamy przypadek 2
       to idź do kroku K30     ; - wujek czarny, X prawy syn
K28:   XXup ; X staje się swoim ojcem
K29:   rot_l(root, X) ; wykonujemy rotację w lewo, 
                     ; X przechodzi do lewego syna
K30:   Xupcolor BLACK  ; przypadek 3
                              ; - wujek czarny, X lewy syn
K31:   Xupupcolor RED  ; zmieniamy kolory ojca i dziadka
K32:   rot_r(root, Xupup) ; wykonujemy rotację w prawo
                             ; względem dziadka
K33:   Idź do kroku K48 ; i wychodzimy z pętli
K34:   YXupupleft ; przypadki lustrzane
K35:   Jeśli Ycolor =  BLACK , 
       to idź do kroku K41
K36:   Xupcolor BLACK 
K37:   Ycolor BLACK 
K38:   Xupupcolor RED 
K39:   XXupup
K40:   Następny obieg pętli K18
K41:   Jeśli XXupleft, 
       to idź do kroku K44
K42:   XXup
K43:   rot_r(root, X)
K44:   Xupcolor BLACK 
K45:   Xupupcolor RED 
K46:   rot_l(root, Xupup)
K47:   Idź do kroku K48 ; wychodzimy z pętli K18
K48: rootcolor ←  BLACK  ; kolorujemy korzeń na czarno
K49: Zakończ

do podrozdziału  do strony 

Usuwanie węzła

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.
obrazek
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.
obrazek
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.
obrazek
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.
obrazek

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*.
obrazek
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*.
obrazek
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.
obrazek
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.
obrazek

Algorytm usuwania węzła z drzewa czerwono-czarnego

Wejście:

root : referencja do zmiennej przechowującej adres korzenia.
X : wskazanie usuwanego węzła.
S : wskazanie węzła strażnika.

Wyjście:

Drzewo czerwono-czarne z usuniętym węzłem X

Elementy pomocnicze:

W, Y, Z : wskazania węzłów.
succ_rbt(p) : zwraca wskazanie następnika w drzewie czerwono-czarnym.
rot_l(root, p) : wykonuje rotację w lewo względem węzła p.
rot_r(root, p) : wykonuje rotację w prawo względem węzła p.

Lista kroków:

K01: Jeśli (Xleft = S) obrazek (Xright = S), 
     to YX ; Y jest usuwanym węzłem, jest to albo X, 
     inaczej Ysucc_rbt(X) ; albo jego następnik
K02: Jeśli YleftS, 
     to ZYleft ; Z jest lewym lub 
     Inaczej ZYright ; prawym synem usuwanego elementu
K03: ZupYup ; Rodzicem Z będzie ojciec Y
K04: Jeśli YupS, ; Sprawdzamy, czy usuwany
     to idź do kroku K07 ; węzeł jest korzeniem
K05: rootZ ; Jeśli tak, to nowym korzeniem
              ; będzie jego syn
K06: Idź do kroku K08 ; Przechodzimy do poprawiania
                      ; struktury drzewa
K07: Jeśli Y = Yupleft, ; Z zastępuje Y w strukturze drzewa
     to YupleftZ
     inaczej YuprightZ
K08: Jeśli YX, ; Jeśli X nie jest usuwanym węzłem, 
     to XkeyYkey ; to przenosimy klucze z Y do X
K09: Jeśli Ycolor =  RED , ; Jeśli usuwany węzeł jestczerwony, 
     to idź do kroku K52    ; to kończymy
K10: Dopóki Zroot obrazek (Zcolor =  BLACK ):
     wykonuj kroki K11…K51 ; Dokonujemy poprawy struktury
                           ; drzewa czerwono-czarnego
K11:   Jeśli Z = Zupright, ; Skok do przypadków lustrzanych
       to idź do kroku K33
K12:   WZupright ; W wskazuje brata Z
K13:   Jeśli Wcolor =  BLACK , 
       to idź do kroku K18
K14:   Wcolor BLACK  ; Przypadek 1
K15:   Zupcolor RED 
K16:  rot_l(root, Zup)
K17:   WZupright
K18:   Jeśli (Wleftcolor =  RED ) obrazek (Wrightcolor =  RED ), 
       to idź do kroku K22
K19:   Wcolor RED  ; Przypadek 2
K20:   ZZup
K21:   Następny obieg pętli K10
K22:   Jeśli Wrightcolor =  RED , 
       to idź do kroku K27
K23:   Wleftcolor BLACK  ; Przypadek 3
K24:   Wcolor RED 
K25:   rot_r(root, W)
K26:   WZupright
K27:   WcolorZupcolor ; Przypadek 4
K28:   Zupcolor BLACK 
K29:   Wrightcolor BLACK 
K30:   rot_l(root, Zup)
K31;   Zroot ; Z = root spowoduje przerwanie pętli
       i następny obieg pętli K10
K32:   WZupleft ; Przypadki lustrzane
K33:   Jeśli Wcolor =  BLACK , 
       to idź do kroku K38
K34:   Wcolor BLACK  ; Przypadek 1
K35:   Zupcolor RED 
K36:   rot_r(root, Zup)
K37:   WZupleft
K38:   Jeśli (Wleftcolor =  RED ) obrazek (Wrightcolor =  RED ), 
       to idź do kroku K42
K39:   Wcolor RED  ; Przypadek 2
K40:   ZZup
K41:   Następny obieg pętli K10
K42:   Jeśli Wleftcolor =  RED , 
       to idź do kroku K47
K43:   Wrightcolor BLACK  ; Przypadek 3
K44:   Wcolor RED 
K45:   rot_l(root, W)
K46:   WZupleft
K47:   WcolorZupcolor ; Przypadek 4
K48:   Zupcolor BLACK 
K49:   Wleftcolor BLACK 
K50:   rot_r(root, Zup)
K51:   Zroot ; Z = root spowoduje przerwanie pętli
       i następny obieg pętli K10
K52: Zcolor BLACK  ; węzeł Z kolorujemy na czarno
K53: Usuń Y
K54: Zakończ

Przykładowe programy

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.
C++
// 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

do podrozdziału  do strony 

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: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.