|
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
|
| SPIS TREŚCI |
|
| Tematy pomocnicze |
Zbiory o dowolnym zakresie wartości elementów można efektywnie realizować za pomocą drzew poszukiwań binarnych BST. Zaletą tych drzew jest szybkość wyszukiwania elementu (O(log n)). Musimy jednakże pamiętać, że zwykłe drzewa BST mogą się degenerować do list liniowych (O(n)). Rozwiązaniem jest stosowanie algorytmu równoważącego drzewo binarne (np. algorytm DSW) lub wybranie innego rodzaju drzew, np. AVL, Splay lub czerwono-czarnych, które automatycznie się równoważą.
W podanych niżej algorytmach nie określamy rodzaju drzew binarnych. Może on być dowolny (BST, AVL, Splay czerwono-czarne lub inne), jednakże każdy węzeł drzewa musi posiadać następujące pola danych:
Wartość elementu może należeć do dowolnego zakresu liczbowego (liczby naturalne, całkowite, rzeczywiste). Również zakres tej wartości jest dowolny.
Oprócz wymienionych pól w strukturze węzła drzewa binarnego mogą się znaleźć pola specyficzne dla danej implementacji. Np. dla drzew czerwono-czarnych pojawi się pole color, które przechowuje informację o kolorze węzła.
Pascaltype
PBTnode = ^BTnode;
BTnode = record
up : PRBTnode;
left : PRBTnode;
right : PRBTnode;
key : typ_danych;
…
end; |
struct BTnode
{
BTnode *up, *left, *right;
typ_danych key;
…
}; |
BasicType BTnode up As BTnode Ptr left As BTnode Ptr right As BTnode Ptr key As typ_danych … End Type |
| Python (dodatek) |
class BTnode:
def __init__(self)
self.up = None
self.left = None
self.right = None
self.key = 0
…
|
Zbiór będzie reprezentowany przez zmienną, która przechowuje adres korzenia drzewa binarnego. Zmienna ta będzie przekazywana przez referencję do procedur obsługujących strukturę zbioru.
K01: Dopóki A wskazuje węzeł drzewa, ; ta operacja jest zależna od wykonuj kroki K02…K03 ; przyjętej struktury drzewa K02: Jeśli (A→key) = x, ; element znaleziony to zakończ z wynikiem A K03: Jeśli x < (A→key), to A ← (A→left) ; szukamy dalej w lewej gałęzi drzewa Inaczej A ← (A→right) ; lub w prawej w zależności od x K04: Zakończ z wynikiem nil ; element nie został znaleziony
K01: Jeśli s_isin(A, x) = nil, ; ta operacja jest zależna od to dodaj węzeł x do drzewa A ; przyjętej struktury drzewa K02: Zakończ
K01: p ← s_isin(A, x) ; pobieramy adres węzła o wartości x K02: Jeśli p ≠ nil, ; ta operacja jest zależna od przyjętej struktury drzewa to usuń z drzewa A węzeł wskazywany przez p K03: Zakończ
K01: JeśliA nie wskazuje węzła, ; ta operacja jest zależna od przyjętej struktury drzewa to zakończ K02: s_clear(A →left ) ; usuwamy rekurencyjnie lewą gałąź K03: s_clear(A →right ) ; usuwamy rekurencyjnie prawą gałąź K04: Usuń węzeł wskazywany przezA K05:A ← węzeł pusty ; ta operacja jest zależna od przyjętej struktury drzewa K06: Zakończ
K01: Jeśli A nie wskazuje węzła, ; ta operacja jest zależna od przyjętej struktury drzewa to zakończ K02: s_add(C, A→key) ; do C wstawiamy węzeł bieżący K03: s_copy(A→left, C) ; rekurencyjnie kopiujemy lewe poddrzewo K04: s_copy(A→right, C) ; rekurencyjnie kopiujemy prawe poddrzewo K05: Zakończ
K01: s_clear(C) ; dla pewności usuwamy wszystkie węzły z C K02: s_copy(A, C) ; kopiujemy A do C K03: s_copy(B, C) ; kopiujemy B do C K04: Zakończ
K01: Jeśli A nie wskazuje węzła, ; ta operacja jest zależna od przyjętej struktury drzewa to zakończ K02: Jeśli s_isin(B, A→key) ≠ nil, ; do C wstawiamy element z A, jeśli jest on również w B to s_add(C, A→key) K03: s_icopy(A→left, B, C) ; rekurencyjnie przetwarzamy lewe poddrzewo K04: s_icopy(A→right, B, C) ; rekurencyjnie przetwarzamy prawe poddrzewo K05: Zakończ
K01: s_clear(C) ; czyścimy drzewo C K02: s_icopy(A, B, C) ; tworzymy w C iloczyn A i B K03: Zakończ
K01: Jeśli A nie wskazuje węzła, ; ta operacja jest zależna od przyjętej struktury drzewa to zakończ K02: Jeśli s_isin(B, A→key) = nil, ; do C wstawiamy element z A, jeśli nie ma go w B to s_add(C, (A→key)) K03: s_dcopy(A→left, C) ; rekurencyjnie przetwarzamy lewe poddrzewo K04: s_dcopy(A→right, C) ; rekurencyjnie przetwarzamy prawe poddrzewo K05: Zakończ
K01: s_clear(C) ; czyścimy drzewo C K02: s_dcopy(A, B, C) ; tworzymy w C różnicę A i B K03: Zakończ
K01: Jeśli A nie wskazuje węzła, ; ta operacja jest zależna od przyjętej struktury drzewa to zakończ z wynikiem true K02: Jeśli s_isin(B, A→key) = nil, ; element z A nie występuje w B to zakończ z wynikiem false K03: Zakończ z wynikiem: s_subset(A→left, B)s_subset(A→right, B) ; przetwarzamy rekurencyjnie węzły potomne
K01: Jeśli A nie wskazuje węzła, ; ta operacja jest zależna od przyjętej struktury drzewa to zakończ K02: cnt ← cnt+1 ; mamy węzeł, zwiększamy licznik K03: s_cnt(A→left, cnt) ; zliczamy węzły w lewym poddrzewie K04: s_cnt(A→right, cnt) ; zliczamy węzły w prawym poddrzewie K05: Zakończ
K01: cnt ← 0 ; zerujemy licznik K02: s_cnt(A, cnt) ; zliczamy węzły K03: Zakończ z wynikiem cnt
K01: Jeśli A nie wskazuje węzła, to zakończ z wynikiem true Inaczej zakończ z wynikiem false ; ta operacja jest zależna od przyjętej struktury drzewa
|
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 testuje wszystkie funkcje obsługi zbiorów opartych na drzewach binarnych. Wyjaśnienie wykonywanych operacji znajduje się w komentarzach wewnątrz programu. Za drzewo binarne przyjęliśmy model drzew czerwono-czarnych. |
Pascal// Zbiory zaimplementowane
// w drzewach czerwono-czarnych
// Data: 9.07.2014
// (C)2014 mgr Jerzy Wałaszek
//-----------------------------
program sets;
// Definicja węzła drzewa
// czerwono-czarnego
type
PRBTnode = ^RBTnode;
RBTnode = record
up : PRBTnode;
left : PRBTnode;
right : PRBTnode;
key : integer;
color : char;
end;
// Zmienne globalne
var
// Węzeł strażnika
S : RBTnode = (up:@S;
left:@S;
right:@S;
key:0;
color:'B');
// Procedury obsługi drzew
// czerwono-czarnych
// Wykonuje rotację
// w lewo względem A
//------------------
procedure rot_L(var root : PRBTnode;
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 rot_R(var root : PRBTnode;
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 insert_rbt(var root : PRBTnode;
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;
// X staje się korzeniem
if X^.up = @S then
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(root, X);
end;
// Przypadek 3
X^.up^.color := 'B';
X^.up^.up^.color := 'R';
rot_R(root, X^.up^.up);
break;
end
else
begin // Przypadki lustrzane
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(root, X);
end;
// Przypadek 3
X^.up^.color := 'B';
X^.up^.up^.color := 'R';
rot_L(root, X^.up^.up);
break;
end;
end;
root^.color := 'B';
end;
// Wyszukuje najmniejszy węzeł
// w poddrzewie o korzeniu p
//----------------------------
function 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 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;
// Usuwa z drzewa węzeł X
//-----------------------
procedure remove_rbt(var root : PRBTnode;
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;
if W^.color = 'R' then
begin // Przypadek 1
W^.color := 'B';
Z^.up^.color := 'R';
rot_L(root, Z^.up);
W := Z^.up^.right;
end;
if (W^.left^.color = 'B') and
(W^.right^.color = 'B') then
begin // Przypadek 2
W^.color := 'R';
Z := Z^.up;
continue;
end;
if W^.right^.color = 'B' then
begin // Przypadek 3
W^.left^.color := 'B';
W^.color := 'R';
rot_R(root, W);
W := Z^.up^.right;
end;
// Przypadek 4
W^.color := Z^.up^.color;
Z^.up^.color := 'B';
W^.right^.color := 'B';
rot_L(root, Z^.up);
// To spowoduje zakończenie pętli
Z := root;
end
else
begin // Przypadki lustrzane
W := Z^.up^.left;
if W^.color = 'R' then
begin // Przypadek 1
W^.color := 'B';
Z^.up^.color := 'R';
rot_R(root, Z^.up);
W := Z^.up^.left;
end;
if (W^.left^.color = 'B') and
(W^.right^.color = 'B') then
begin // Przypadek 2
W^.color := 'R';
Z := Z^.up;
continue;
end;
if W^.left^.color = 'B' then
begin // Przypadek 3
W^.right^.color := 'B';
W^.color := 'R';
rot_L(root, W);
W := Z^.up^.left;
end;
// Przypadek 4
W^.color := Z^.up^.color;
Z^.up^.color := 'B';
W^.left^.color := 'B';
rot_R(root, Z^.up);
// To spowoduje zakończenie pętli
Z := root;
end;
Z^.color := 'B';
dispose(Y);
end;
// Procedury obsługi zbioru
// Szuka w drzewie węzła
// o danej wartości klucza x.
// Jeśli węzeł zostanie
// znaleziony, to zwraca jego adres.
// Inaczej zwraca wskazanie puste.
//----------------------------------
function s_isin(A : PRBTnode;
x : integer)
: PRBTnode;
begin
while A <> @S do
begin
// Węzeł znaleziony
if A^.key = x then Exit(A);
if x < A^.key then
A := A^.left
else
A := A^.right;
end;
// Węzeł nieznaleziony
s_isin := nil;
end;
// Dodaje do drzewa nowy węzeł,
// jeśli w drzewie takiego węzła
// jeszcze nie ma
//------------------------------
procedure s_add(var A : PRBTnode;
x : integer);
begin
if s_isin(A, x) = nil then
insert_rbt(A, x);
end;
// Wyszukuje w drzewie węzeł
// o kluczu x i usuwa go
//--------------------------
procedure s_remove(var A : PRBTnode;
x : integer);
var
p : PRBTnode;
begin
// Szukamy węzła o kluczu x
p := s_isin(A, x);
if p <> nil then
remove_rbt(A, p);
end;
// Usuwa wszystkie węzły z drzewa
//-------------------------------
procedure s_clear(var A : PRBTnode);
begin
if A <> @S then
begin
// Rekurencyjnie usuwamy
// lewe poddrzewo
s_clear(A^.left);
// Rekurencyjnie usuwamy
// prawe poddrzewo
s_clear(A^.right);
// Usuwamy węzeł
dispose(A);
A := @S;
end;
end;
// Procedura kopiuje elementy
// z drzewa A do C
//---------------------------
procedure s_copy(A : PRBTnode;
var C : PRBTnode);
begin
if A <> @S then
begin
// Dodajemy do C klucz
// bieżącego węzła
s_add(C, A^.key);
// Rekurencyjnie dodajemy
// do C lewe poddrzewo
s_copy(A^.left, C);
// Rekurencyjnie dodajemy
// do C prawe poddrzewo
s_copy(A^.right, C);
end;
end;
// Procedura tworzy sumę
// zbiorów A i B w C
//----------------------
procedure s_union(A, B : PRBTnode;
var C : PRBTnode);
begin
// Czyścimy C
s_clear(C);
// W C umieszczamy A
s_copy(A, C);
// Dodajemy B do C
s_copy(B, C);
end;
// Procedura kopiuje do C
// te elementy A, które
// również są w B
//-----------------------
procedure s_icopy(A, B : PRBTnode;
var C : PRBTnode);
begin
if A <> @S then
begin
if s_isin(B, A^.key) <> nil then
s_add(C, A^.key);
s_icopy(A^.left, B, C);
s_icopy(A^.right, B, C);
end;
end;
// Procedura tworzy w C
// iloczyn zbiorów A i B
//----------------------
procedure s_intersection(A, B : PRBTnode;
var C : PRBTnode);
begin
// Czyścimy C
s_clear(C);
// Tworzymy iloczyn zbiorów
s_icopy(A, B, C);
end;
// Procedura kopiuje do C
// te elementy A, których
// nie ma w B
//-----------------------
procedure s_dcopy(A, B : PRBTnode;
var C : PRBTnode);
begin
if A <> @S then
begin
if s_isin(B, A^.key) = nil then
s_add(C, A^.key);
s_dcopy(A^.left, B, C);
s_dcopy(A^.right, B, C);
end;
end;
// Procedura tworzy w C
// różnicę zbiorów A i B
//----------------------
procedure s_difference(A, B : PRBTnode;
var C : PRBTnode);
begin
// Czyścimy C
s_clear(C);
// Tworzymy różnicę zbiorów
s_dcopy(A, B, C);
end;
// Funkcja zwraca true,
// jeśli zbiór A jest
// podzbiorem B
//---------------------
function s_subset(A, B : PRBTnode)
: boolean;
begin
if A = @S then Exit(true);
if s_isin(B, A^.key) = nil then
Exit(false);
s_subset := s_subset(A^.left, B) and
s_subset(A^.right, B);
end;
// Procedura zlicza rekurencyjnie
// węzły w drzewie
//-------------------------------
procedure s_cnt(A : PRBTnode;
var cnt : integer);
begin
if A <> @S then
begin
// Zliczamy węzeł bieżący
inc(cnt);
// Rekurencyjnie liczymy węzły
// w lewym poddrzewie
s_cnt(A^.left, cnt);
// Rekurencyjnie liczymy węzły
// w prawym poddrzewie
s_cnt(A^.right, cnt);
end;
end;
// Funkcja oblicza liczbę
// węzłów w drzewie
//-----------------------
function s_size(A : PRBTnode)
: integer;
var
// Licznik węzłów
cnt : integer;
begin
// Zerujemy licznik
cnt := 0;
// Zliczamy węzły
s_cnt(A, cnt);
// Zwracamy wynik
s_size := cnt;
end;
// Funkcja zwraca true,
// jeśli zbiór jest pusty
//-----------------------
function s_empty(A : PRBTnode)
: boolean;
begin
s_empty := A = @S;
end;
// Procedura rekurencyjnie
// wyświetla zawartość drzewa
//---------------------------
procedure s_print(A : PRBTnode);
begin
if A <> @S then
begin
s_print(A^.left);
write(A^.key, ' ');
s_print(A^.right);
end;
end;
// **********************
// *** PROGRAM GŁÓWNY ***
// **********************
var
A, B, C, D : PRBTnode;
i, x : integer;
begin
randomize;
// Tworzymy puste zbiory
A := @S;
B := @S;
C := @S;
D := @S;
// Do zbioru A dodajemy 10 losowych elementów
for i := 1 to 10 do
s_add(A, -20+random(41));
// Do zbioru B dodajemy 15 losowych elementów
for i := 1 to 15 do
s_add(B, -20+random(41));
// Wyświetlamy je
writeln('A:');
s_print(A); writeln;
writeln('SIZE OF A IS ', s_size(A));
writeln;
writeln('B:');
s_print (B); writeln;
writeln('SIZE OF B IS ', s_size(B));
// Suma zbiorów
writeln;
writeln('UNION OF A AND B:');
s_union(A, B, C);
s_print(C); writeln;
writeln('SIZE OF UNION IS ', s_size(C));
// Iloczyn zbiorów
writeln;
writeln('INTERSECTION OF A AND B:');
s_intersection(A, B, C);
s_print(C); writeln;
writeln('SIZE OF INTERSECTION IS ', s_size(C));
// Różnica zbiorów
writeln;
writeln('DIFFERENCE OF A AND B:');
s_difference(A, B, C);
s_print(C); writeln;
writeln('SIZE OF DIFFERENCE IS ', s_size(C));
// Podzbiór
// Kopiujemy A do C
s_union(A, A, C);
// Usuwamy 7 elementów
for i := 1 to 7 do
s_remove(C, -20+random(41));
writeln;
writeln('IS:');
s_print(C);
writeln(' SUBSET OF A?');
writeln(s_subset(C, A));
s_difference(B, A, C);
// Usuwamy 12 elementów
for i := 1 to 12 do
s_remove(C, -20+random(41));
writeln;
writeln('IS:');
s_print(C);
writeln(' SUBSET OF A?');
writeln(s_subset(C, A));
// Usuwanie
writeln;
write('FROM A WE REMOVE');
for i := 1 to 5 do
begin
x := -20+random(41);
write(x:4);
s_remove(A, x);
end;
writeln;
writeln('A:'); s_print(A); writeln;
writeln('SIZE OF A IS ', s_size(A));
writeln;
// Sprawdzamy obecność wybranych
// elementów w B
for i := 1 to 10 do
begin
x := -20+random(41);
write('IS ELEMENT', x:4, ' IN SET B? ');
if s_isin(B, x) <> nil then
writeln('YES')
else
writeln('NO');
end;
writeln;
// Sprawdzenie testu na zbiór pusty
writeln('IS SET A EMPTY?');
writeln(s_empty(A));
writeln;
writeln('IS INTERSECTION OF A AND DIFFERENCE' +
' OF B AND A EMPTY?');
s_difference(B, A, C);
s_intersection(A, C, D);
writeln(s_empty(D));
writeln;
// Usuwamy zbiory
s_clear(A);
s_clear(B);
s_clear(C);
s_clear(D);
end.
|
C++// Zbiory zaimplementowane
// w drzewach czerwono-czarnych
// Data: 9.07.2014
// (C)2014 mgr Jerzy Wałaszek
//-----------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
using namespace std;
// Definicja węzła drzewa
// czerwono-czarnego
struct RBTnode
{
RBTnode * up;
RBTnode * left;
RBTnode * right;
int key;
char color;
};
// Zmienne globalne
RBTnode S = {&S, &S, &S, 0, 'B'};
// Procedury obsługi drzew czerwono-czarnych
// Wykonuje rotację w lewo
// względem A
//------------------------
void rot_L(RBTnode * & root,
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 rot_R(RBTnode * & root,
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 insert_rbt(RBTnode * & root,
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(root, X);
}
// Przypadek 3
X->up->color = 'B';
X->up->up->color = 'R';
rot_R(root, 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(root, X);
}
// Przypadek 3
X->up->color = 'B';
X->up->up->color = 'R';
rot_L(root, X->up->up);
break;
}
}
root->color = 'B';
}
// Wyszukuje najmniejszy węzeł
// w poddrzewie o korzeniu p
//----------------------------
RBTnode * min_rbt(RBTnode * p)
{
if(p != &S)
while(p->left != &S)
p = p->left;
return p;
}
// Zwraca następnik p
//-------------------
RBTnode * 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;
}
// Usuwa z drzewa węzeł X
//-----------------------
void remove_rbt(RBTnode * & root,
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(root, 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(root, W);
W = Z->up->right;
}
// Przypadek 4
W->color = Z->up->color;
Z->up->color = 'B';
W->right->color = 'B';
rot_L(root, 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(root, 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(root, W);
W = Z->up->left;
}
// Przypadek 4
W->color = Z->up->color;
Z->up->color = 'B';
W->left->color = 'B';
rot_R(root, Z->up);
// To spowoduje zakończenie pętli
Z = root;
}
}
Z->color = 'B';
delete Y;
}
// Procedury obsługi zbioru
// Szuka w drzewie węzła
// o danej wartości klucza x.
// Jeśli węzeł zostanie znaleziony,
// to zwraca jego adres.
// Inaczej zwraca wskazanie puste.
//---------------------------------
RBTnode * s_isin(RBTnode * A,
int x)
{
while(A != &S)
{
// Węzeł znaleziony
if(A->key == x) return A;
if(x < A->key)
A = A->left;
else
A = A->right;
}
// Węzeł nieznaleziony
return NULL;
}
// Dodaje do drzewa nowy węzeł,
// jeśli w drzewie takiego węzła
// jeszcze nie ma
//------------------------------
void s_add(RBTnode * & A,
int x)
{
if(!s_isin(A, x))
insert_rbt(A, x);
}
// Wyszukuje w drzewie węzeł o kluczu x i usuwa go
//------------------------------------------------
void s_remove(RBTnode * & A,
int x)
{
// Szukamy węzła o kluczu x
RBTnode * p = s_isin(A, x);
if(p) remove_rbt(A, p);
}
// Usuwa wszystkie węzły z drzewa
//-------------------------------
void s_clear(RBTnode * & A)
{
if(A != &S)
{
// Rekurencyjnie usuwamy
// lewe poddrzewo
s_clear(A->left);
// Rekurencyjnie usuwamy
// prawe poddrzewo
s_clear(A->right);
// Usuwamy węzeł
delete A;
A = &S;
}
}
// Procedura kopiuje elementy
// z drzewa A do C
//---------------------------
void s_copy(RBTnode * A,
RBTnode * & C)
{
if(A != &S)
{
// Dodajemy do C klucz
// bieżącego węzła
s_add(C, A->key);
// Rekurencyjnie dodajemy do C
// lewe poddrzewo
s_copy(A->left, C);
// Rekurencyjnie dodajemy do C
// prawe poddrzewo
s_copy(A->right, C);
}
}
// Procedura tworzy sumę
// zbiorów A i B w C
//----------------------
void s_union(RBTnode * A,
RBTnode * B,
RBTnode * & C)
{
// Czyścimy C
s_clear (C);
// W C umieszczamy A
s_copy(A, C);
// Dodajemy B do C
s_copy(B, C);
}
// Procedura kopiuje do C
// te elementy A, które
// również są w B
//-----------------------
void s_icopy(RBTnode * A,
RBTnode * B,
RBTnode * & C)
{
if(A != &S)
{
if(s_isin(B, A->key))
s_add(C, A->key);
s_icopy(A->left, B, C);
s_icopy(A->right, B, C);
}
}
// Procedura tworzy w C iloczyn
// zbiorów A i B
//-----------------------------
void s_intersection(RBTnode * A,
RBTnode * B,
RBTnode * & C)
{
// Czyścimy C
s_clear(C);
// Tworzymy iloczyn zbiorów
s_icopy(A, B, C);
}
// Procedura kopiuje do C te elementy A,
// których nie ma w B
//--------------------------------------
void s_dcopy(RBTnode * A,
RBTnode * B,
RBTnode * & C)
{
if(A != &S)
{
if(!s_isin(B, A->key))
s_add(C, A->key);
s_dcopy(A->left, B, C);
s_dcopy(A->right, B, C);
}
}
// Procedura tworzy w C różnicę
// zbiorów A i B
//-----------------------------
void s_difference(RBTnode * A,
RBTnode * B,
RBTnode * & C)
{
// Czyścimy C
s_clear(C);
// Tworzymy różnicę zbiorów
s_dcopy(A, B, C);
}
// Funkcja zwraca true, jeśli zbiór A
// jest podzbiorem B
//-----------------------------------
bool s_subset(RBTnode * A,
RBTnode * B)
{
if(A == &S) return true;
if(!s_isin(B, A->key)) return false;
return s_subset(A->left, B) &&
s_subset(A->right, B);
}
// Procedura zlicza rekurencyjnie
// węzły w drzewie
//-------------------------------
void s_cnt(RBTnode * A,
int & cnt)
{
if(A != &S)
{
// Zliczamy węzeł bieżący
cnt++;
// Rekurencyjnie liczymy węzły
// w lewym poddrzewie
s_cnt(A->left, cnt);
// Rekurencyjnie liczymy węzły
// w prawym poddrzewie
s_cnt(A->right, cnt);
}
}
// Funkcja oblicza liczbę
// węzłów w drzewie
//-----------------------
int s_size(RBTnode * A)
{
// Zerujemy licznik
int cnt = 0;
// Zliczamy węzły
s_cnt(A, cnt);
// Zwracamy wynik
return cnt;
}
// Funkcja zwraca true,
// jeśli zbiór jest pusty
//-----------------------
bool s_empty(RBTnode * A)
{
return A == &S;
}
// Procedura rekurencyjnie wyświetla
// zawartość drzewa
//----------------------------------
void s_print(RBTnode * A)
{
if(A != &S)
{
s_print(A->left);
cout << A->key << " ";
s_print(A->right);
}
}
// **********************
// *** PROGRAM GŁÓWNY ***
// **********************
int main()
{
RBTnode *A, *B, *C, *D;
int i, x;
srand(time(NULL));
// Tworzymy puste zbiory
A = B = C = D = &S;
// Do zbioru A dodajemy 10
// losowych elementów
for(i = 0; i < 10; i++)
s_add(A, -20+(rand() % 41));
// Do zbioru B dodajemy 15
// losowych elementów
for(i = 0; i < 15; i++)
s_add(B, -20+(rand() % 41));
// Wyświetlamy je
cout << "A:" << endl;
s_print(A);
cout << endl << "SIZE OF A IS "
<< s_size(A) << endl
<< endl << "B:" << endl;
s_print (B);
cout << endl << "SIZE OF B IS "
<< s_size(B) << endl << endl
// Suma zbiorów
<< "UNION OF A AND B:" << endl;
s_union(A, B, C);
s_print(C);
cout << endl << "SIZE OF UNION IS "
<< s_size(C) << endl << endl
// Iloczyn zbiorów
<< "INTERSECTION OF A AND B:" << endl;
s_intersection(A, B, C);
s_print(C);
cout << endl << "SIZE OF INTERSECTION IS "
<< s_size(C) << endl << endl
// Różnica zbiorów
<< "DIFFERENCE OF A AND B:" << endl;
s_difference(A, B, C);
s_print(C);
cout << endl << "SIZE OF DIFFERENCE IS "
<< s_size(C) << endl << endl;
// Podzbiór
// Kopiujemy A do C
s_union(A, A, C);
// Usuwamy 7 elementów
for(i = 0; i < 7; i++)
s_remove(C, -20+(rand() % 41));
cout << "IS:" << endl;
s_print(C);
cout << " SUBSET OF A?" << endl
<< (s_subset(C, A) ? "YES": "NO")
<< endl << endl;
s_difference(B, A, C);
// Usuwamy 12 elementów
for(i = 0; i < 12; i++)
s_remove(C, -20+(rand() % 41));
cout << "IS:" << endl;
s_print(C);
cout << " SUBSET OF A?" << endl
<< (s_subset(C, A) ? "YES": "NO")
<< endl << endl
// Usuwanie
<< "FROM A WE REMOVE";
for(i = 0; i < 5; i++)
{
x = -20+(rand() % 41);
cout << setw(4) << x;
s_remove(A, x);
}
cout << endl << "A:" << endl;
s_print(A);
cout << endl << "SIZE OF A IS "
<< s_size(A) << endl << endl;
// Sprawdzamy obecność wybranych
// elementów w B
for(i = 0; i < 10; i++)
{
x = -20+(rand() % 41);
cout << "IS ELEMENT" << setw(4)
<< x << " IN SET B? "
<< (s_isin(B, x) ? "YES": "NO")
<< endl;
}
// Sprawdzenie testu na zbiór pusty
cout << endl << "IS SET A EMPTY?" << endl
<< (s_empty(A) ? "YES": "NO")
<< endl << endl
<< "IS INTERSECTION OF A AND DIFFERENCE"
" OF B AND A EMPTY?" << endl;
s_difference(B, A, C);
s_intersection(A, C, D);
cout << (s_empty(D) ? "YES": "NO")
<< endl << endl;
// Usuwamy tablice dynamiczne w zbiorach
s_clear(A);
s_clear(B);
s_clear(C);
s_clear(D);
return 0;
}
|
Basic' Zbiory zaimplementowane
' w drzewach czerwono-czarnych
' Data: 9.07.2014
' (C)2014 mgr Jerzy Wałaszek
'-----------------------------
' Definicja węzła drzewa czerwono-czarnego
Type RBTnode
up As RBTnode Ptr
left As RBTnode Ptr
right As RBTnode Ptr
key As Integer
color As String * 1
End Type
' Zmienne globalne
Dim Shared As RBTnode S _
=> (@S, @S, @S, 0, "B")
' Procedury obsługi drzew czerwono-czarnych
' Wykonuje rotację w lewo względem A
'-----------------------------------
Sub rot_L(ByRef root As RBTnode Ptr, _
ByVal 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 rot_R(ByRef root As RBTnode Ptr, _
ByVal 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 insert_rbt(ByRef root As RBTnode Ptr, _
ByVal k As Integer)
Dim As RBTnode Ptr X, Y
X = new RBTnode ' Tworzymy nowy węzeł
X->left = @S ' Inicjujemy pola
X->right = @S
X->up = root
X->key = k
If X->up = @S Then
root = X ' X staje się korzeniem
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 = X->up->up->Right ' Y -> wujek X
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(root, X)
End If
X->up->color = "B" ' Przypadek 3
X->up->up->color = "R"
rot_R(root, 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(root, X)
End If
X->up->color = "B" ' Przypadek 3
X->up->up->color = "R"
rot_L(root, X->up->up)
Exit While
End If
Wend
root->color = "B"
End Sub
' Wyszukuje najmniejszy węzeł w poddrzewie
' o korzeniu p
'-----------------------------------------
Function min_rbt(ByVal p As RBTnode Ptr) _
As RBTnode Ptr
If p <> @S Then
While p->left <> @S
p = p->Left
Wend
End If
Return p
End Function
' Zwraca następnik p
'-------------------
Function succ_rbt(ByVal 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
' Usuwa z drzewa węzeł X
'-----------------------
Sub remove_rbt(ByRef root As RBTnode Ptr, _
ByVal 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
' Naprawa struktury drzewa
' czerwono-czarnego
If Y->color = "B" Then
While (Z <> root) AndAlso _
(Z->color = "B")
If Z = Z->up->Left Then
W = Z->up->Right
' Przypadek 1
If W->color = "R" Then
W->color = "B"
Z->up->color = "R"
rot_L(root, Z->up)
W = Z->up->Right
End If
' Przypadek 2
If (W->left->color = "B") AndAlso _
(W->right->color = "B") Then
W->color = "R"
Z = Z->up
Continue While
End If
' Przypadek 3
If W->right->color = "B" Then
W->left->color = "B"
W->color = "R"
rot_R(root, W)
W = Z->up->Right
End If
' Przypadek 4
W->color = Z->up->Color
Z->up->color = "B"
W->right->color = "B"
rot_L(root, Z->up)
' To spowoduje zakończenie pętli
Z = root
Else ' Przypadki lustrzane
W = Z->up->Left
' Przypadek 1
If W->color = "R" Then
W->color = "B"
Z->up->color = "R"
rot_R(root, Z->up)
W = Z->up->Left
End If
' Przypadek 2
If (W->left->color = "B") AndAlso _
(W->right->color = "B") Then
W->color = "R"
Z = Z->up
Continue While
End If
' Przypadek 3
If W->left->color = "B" Then
W->right->color = "B"
W->color = "R"
rot_L(root, W)
W = Z->up->Left
End If
' Przypadek 4
W->color = Z->up->Color
Z->up->color = "B"
W->left->color = "B"
rot_R(root, Z->up)
' To spowoduje zakończenie pętli
Z = root
End If
Wend
End If
Z->color = "B"
Delete Y
End Sub
' Procedury obsługi zbioru
' Szuka w drzewie węzła o danej wartości
' klucza x. Jeśli węzeł zostanie znaleziony,
' to zwraca jego adres. Inaczej zwraca
' wskazanie puste.
'-------------------------------------------
Function s_isin(ByVal A As RBTnode Ptr, _
ByVal x As Integer) _
As RBTnode Ptr
While A <> @S
' Węzeł znaleziony
If A->key = x Then Return A
If x < A->key Then
A = A->Left
Else
A = A->Right
End If
Wend
Return 0 ' Węzeł nieznaleziony
End Function
' Dodaje do drzewa nowy węzeł,
' jesli w drzewie takiego węzła
' jeszcze nie ma
'------------------------------
Sub s_add(ByRef A As RBTnode Ptr, _
ByVal x As Integer)
If s_isin(A, x) = 0 Then insert_rbt(A, x)
End Sub
' Wyszukuje w drzewie węzeł o kluczu x
' i usuwa go
'-------------------------------------
Sub s_remove(ByRef A As RBTnode Ptr, _
ByVal x As Integer)
' Szukamy węzła o kluczu x
Dim As RBTnode Ptr p = s_isin (A, x)
If p Then remove_rbt(A, p)
End Sub
' Usuwa wszystkie węzły z drzewa
'-------------------------------
Sub s_clear(ByRef A As RBTnode Ptr)
If A <> @S Then
' Rekurencyjnie usuwamy lewe poddrzewo
s_clear(A->left)
' Rekurencyjnie usuwamy prawe poddrzewo
s_clear(A->right)
Delete A ' Usuwamy węzeł
A = @S
End If
End Sub
' Procedura kopiuje elementy z drzewa A do C
'-------------------------------------------
Sub s_copy(Byval A As RBTnode Ptr, _
ByRef C As RBTnode Ptr)
If A <> @S Then
' Dodajemy do C klucz bieżącego węzła
s_add(C, A->key)
' Rekurencyjnie dodajemy do C
' lewe poddrzewo
s_copy(A->left, C)
' Rekurencyjnie dodajemy do C
' prawe poddrzewo
s_copy(A->right, C)
End If
End Sub
' Procedura tworzy sumę zbiorów A i B w C
'----------------------------------------
Sub s_union(ByVal A As RBTnode Ptr, _
ByVal B As RBTnode Ptr, _
ByRef C As RBTnode Ptr)
s_clear(C) ' Czyścimy C
s_copy(A, C) ' W C umieszczamy A
s_copy(B, C) ' Dodajemy B do C
End Sub
' Procedura kopiuje do C te elementy A,
' które również są w B
'--------------------------------------
Sub s_icopy(ByVal A As RBTnode Ptr, _
ByVal B As RBTnode Ptr, _
ByRef C As RBTnode Ptr)
If A <> @S Then
If s_isin(B, A->key) Then _
s_add(C, A->key)
s_icopy(A->left, B, C)
s_icopy(A->right, B, C)
End If
End Sub
' Procedura tworzy w C iloczyn zbiorów A i B
'-------------------------------------------
Sub s_intersection(ByVal A As RBTnode Ptr, _
ByVal B As RBTnode Ptr, _
ByRef C As RBTnode Ptr)
' Czyścimy C
s_clear(C)
' Tworzymy iloczyn zbiorów
s_icopy(A, B, C)
End Sub
' Procedura kopiuje do C te elementy A,
' których nie ma w B
'--------------------------------------
Sub s_dcopy(ByVal A As RBTnode Ptr, _
ByVal B As RBTnode Ptr, _
ByRef C As RBTnode Ptr)
If A <> @S Then
If s_isin(B, A->key) = 0 Then _
s_add(C, A->key)
s_dcopy(A->left, B, C)
s_dcopy(A->right, B, C)
End If
End Sub
' Procedura tworzy w C różnicę zbiorów A i B
'-------------------------------------------
Sub s_difference(ByVal A As RBTnode Ptr, _
ByVal B As RBTnode Ptr, _
ByRef C As RBTnode Ptr)
' Czyścimy C
s_clear(C)
' Tworzymy różnicę zbiorów
s_dcopy(A, B, C)
End Sub
' Funkcja zwraca true, jeśli zbiór A
' jest podzbiorem B
' Inaczej zwraca false
'-----------------------------------
Function s_subset(ByVal A As RBTnode Ptr, _
ByVal B As RBTnode Ptr) _
As Integer
If A = @S Then Return -1
If s_isin(B, A->key) = 0 Then Return 0
Return s_subset(A->left, B) AndAlso _
s_subset(A->right, B)
End Function
' Procedura zlicza rekurencyjnie węzły
' w drzewie
'-------------------------------------
Sub s_cnt(ByVal A As RBTnode Ptr, _
ByRef cnt As Integer)
If A <> @S Then
' Zliczamy węzeł bieżący
cnt += 1
' Rekurencyjnie liczymy węzły
' w lewym poddrzewie
s_cnt(A->left, cnt)
' Rekurencyjnie liczymy węzły
' w prawym poddrzewie
s_cnt(A->right, cnt)
End If
End Sub
' Funkcja oblicza liczbę węzłów w drzewie
'----------------------------------------
Function s_size(ByVal A As RBTnode Ptr) _
As Integer
' Zerujemy licznik
Dim As Integer cnt = 0
s_cnt(A, cnt) ' Zliczamy węzły
Return cnt ' Zwracamy wynik
End Function
' Funkcja zwraca true,
' jeśli zbiór jest pusty
'-----------------------
Function s_empty(ByVal A As RBTnode Ptr) _
As Integer
Return A = @S
End Function
' Procedura rekurencyjnie wyświetla
' zawartość drzewa
'----------------------------------
Sub s_print(byval A As RBTnode Ptr)
If A <> @S Then
s_print(A->left)
Print Using "& ";A->key;
s_print(A->right)
End If
End Sub
' **********************
' *** PROGRAM GŁÓWNY ***
' **********************
Dim As RBTnode Ptr A, B, C, D
Dim As Integer i, x
Randomize
' Tworzymy puste zbiory
A = @S
B = @S
C = @S
D = @S
' Do zbioru A dodajemy
' 10 losowych elementów
For i = 1 To 10
s_add(A, -20+Int(rnd()*41))
Next
' Do zbioru B dodajemy
' 15 losowych elementów
For i = 1 To 15
s_add(B, -20+Int(Rnd()*41))
Next
' Wyświetlamy je
Print "A:"
s_print(A): Print
Print "SIZE OF A IS";s_size(A)
Print
Print "B:"
s_print(B): Print
Print "SIZE OF B IS";s_size(B)
Print
' Suma zbiorów
Print "UNION OF A AND B:"
s_union(A, B, C)
s_print(C): Print
Print "SIZE OF UNION IS";s_size(C)
Print
' Iloczyn zbiorów
Print "INTERSECTION OF A AND B:"
s_intersection(A, B, C)
s_print(C): Print
Print "SIZE OF INTERSECTION IS";s_size(C)
Print
' Różnica zbiorów
Print "DIFFERENCE OF A AND B:"
s_difference(A, B, C)
s_print(C): Print
Print "SIZE OF DIFFERENCE IS";s_size(C)
Print
' Podzbiór
' Kopiujemy A do C
s_union(A, A, C)
' Usuwamy 7 elementów
For i = 1 To 7
s_remove(C, -20+Int(Rnd()*41))
Next
Print "IS:";
s_print(C)
Print " SUBSET OF A?"
If s_subset(C, A) Then
Print "YES"
Else
Print "NO"
End If
Print
s_difference(B, A, C)
' Usuwamy 12 elementów
For i = 1 To 12
s_remove(C, -20+Int(Rnd()*41))
Next
Print "IS:"
s_print(C)
Print " SUBSET OF A?"
If s_subset(C, A) Then
Print "YES"
Else
Print "NO"
End If
Print
' Usuwanie
Print "FROM A WE REMOVE";
For i = 1 To 5
x = -20+Int(Rnd()*41)
Print Using "& ";x;
s_remove(A, x)
Next
Print
Print "A:"
s_print(A): Print
Print "SIZE OF A IS";s_size(A)
Print
' Sprawdzamy obecność wybranych
' elementów w B
For i = 1 To 10
x = -20+Int(Rnd()*41)
Print Using "IS ELEMENT#### IN SET B? ";x;
If s_isin(B, x) Then
Print "YES"
Else
Print "NO"
End If
Next
Print
' Sprawdzenie testu na zbiór pusty
Print "IS SET A EMPTY?"
If s_empty(A) Then
Print "YES"
Else
Print "NO"
End If
Print
Print "IS INTERSECTION OF A AND " + _
"DIFFERENCE OF B AND A EMPTY?"
s_difference(B, A, C)
s_intersection(A, C, C)
If s_empty(C) Then
Print "YES"
Else
Print "NO"
End If
Print
' Usuwamy zbiory
s_clear(A)
s_clear(B)
s_clear(C)
s_clear(D)
End
|
| Python (dodatek) |
# Zbiory zaimplementowane
# w drzewach czerwono-czarnych
# Data 22.09.2024
# (C)2024 mgr Jerzy Wałaszek
#-----------------------------
import random
# klasa węzłów drzewa
class RBTnode:
# Konstruktor
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):
# 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
# 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"
# 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
# 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"
# wyszukuje węzeł o kluczu k
# jeśli węzeł nie zostanie
# znaleziony, to zwraca
# wskazanie puste None
def s_isin(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
# dodaje do drzewa nowy węzeł,
# jesli w drzewie takiego węzła
# jeszcze nie ma
def s_add(self, x):
if not self.s_isin(x):
self.insert_rbt(x)
# wyszukuje w drzewie węzeł
# o kluczu x i usuwa go
def s_remove(self, x):
# Szukamy węzła o kluczu x
p = self.s_isin(x)
if p:
self.remove_rbt(p)
# usuwa wszystkie węzły z drzewa
def s_clear(self):
self.root = self.s
# kopiuje elementy z drzewa A
def s_copy(self, a, x):
if x is not a.s:
# Dodajemy klucz bieżącego węzła
self.s_add(x.key)
# Rekurencyjnie dodajemy
# lewe poddrzewo
self.s_copy(a, x.left)
# Rekurencyjnie dodajemy
# prawe poddrzewo
self.s_copy(a, x.right)
# tworzy sumę zbiorów A i B
def s_union(self, a, b):
self.s_clear() # Czyścimy
self.s_copy(a, a.root) # umieszczamy A
self.s_copy(b, b.root) # dodajemy B
# kopiuje elementy A,
# które również są w B
def s_icopy(self, a, x, b):
if x is not a.s:
if b.s_isin(x.key):
self.s_add(x.key)
self.s_icopy(a, x.left, b)
self.s_icopy(a, x.right, b)
# tworzy iloczyn zbiorów A i B
def s_intersection(self, a, b):
# Czyścimy
self.s_clear()
# Tworzymy iloczyn zbiorów
self.s_icopy(a, a.root, b)
# kopiuje te elementy A,
# których nie ma w B
def s_dcopy(self, a, x, b,):
if x is not a.s:
if not b.s_isin(x.key):
self.s_add(x.key)
self.s_dcopy(a, x.left, b)
self.s_dcopy(a, x.right, b)
# tworzy różnicę zbiorów A i B
def s_difference(self, a, b):
# Czyścimy
self.s_clear()
# Tworzymy różnicę zbiorów
self.s_dcopy(a, a.root, b)
# zwraca true, jeśli zbiór A
# jest podzbiorem zbioru
# Inaczej zwraca false
def s_scopy(self, a, x):
if x is a.s:
return True
if not self.s_isin(x.key):
return False
return self.s_scopy(a, x.left) and \
self.s_scopy(a, x.right)
# zwraca true, jeśli zbiór A
# jest podzbiorem
# Inaczej zwraca false
def s_subset(self, a):
return self.s_scopy(a, a.root)
# zlicza rekurencyjnie węzły w drzewie
def s_cnt(self, x, cnt):
if x is not self.s:
cnt += 1
# Rekurencyjnie liczymy węzły
# w lewym poddrzewie
cnt = self.s_cnt(x.left, cnt)
# Rekurencyjnie liczymy węzły
# w prawym poddrzewie
cnt = self.s_cnt(x.right, cnt)
return cnt
# oblicza liczbę węzłów w drzewie
def s_size(self):
# Zliczamy węzły i zwracamy
return self.s_cnt(self.root, 0)
# zwraca true, zbiór jest pusty
def s_empty(self):
return self.root is self.s
# rekurencyjnie wyświetla
# zawartość drzewa
def s_print_rbt(self, x):
if x is not self.s:
self.s_print_rbt(x.left)
print(x.key, end=" ")
self.s_print_rbt(x.right)
def s_print(self):
self.s_print_rbt(self.root)
# **********************
# *** PROGRAM GŁÓWNY ***
# **********************
a = RBtree()
b = RBtree()
c = RBtree()
# Do zbioru A dodajemy 10 losowych elementów
for i in range(10):
a.s_add(random.randrange(-20,21))
# Do zbioru B dodajemy 15 losowych elementów
for i in range(15):
b.s_add(random.randrange(-20,21))
# Wyświetlamy je
print("A:")
a.s_print()
print()
print("SIZE OF A IS", a.s_size())
print()
print("B:")
b.s_print()
print()
print("SIZE OF B IS", b.s_size())
print()
# Suma zbiorów
print("UNION OF A AND B:")
c.s_union(a, b)
c.s_print()
print()
print("SIZE OF UNION IS", c.s_size())
print()
# Iloczyn zbiorów
print("INTERSECTION OF A AND B:")
c.s_intersection(a, b)
c.s_print()
print()
print("SIZE OF INTERSECTION IS", c.s_size())
print()
# Różnica zbiorów
print("DIFFERENCE OF A AND B:")
c.s_difference(a, b)
c.s_print()
print()
print("SIZE OF DIFFERENCE IS", c.s_size())
print()
# Podzbiór
# Kopiujemy A
c.s_union(a, a)
# Usuwamy 7 elementów
for i in range(7):
c.s_remove(random.randrange(-20,21))
print("IS:", end=" ")
c.s_print()
print(" SUBSET OF A?")
if a.s_subset(c):
print("YES")
else:
print("NO")
print()
c.s_difference(b, a)
# Usuwamy 12 elementów
for i in range(12):
c.s_remove(random.randrange(-20,21))
print("IS:", end=" ")
c.s_print()
print(" SUBSET OF A?")
if a.s_subset(c):
print("YES")
else:
print("NO")
print()
# Usuwanie
print("FROM A WE REMOVE", end=" ")
for i in range(5):
x = random.randrange(-20,21)
print(x, end=" ")
a.s_remove(x)
print()
print("A:")
a.s_print()
print()
print("SIZE OF A IS", a.s_size())
print()
# Sprawdzamy obecność wybranych
# elementów w B
for i in range(10):
x = random.randrange(-20, 21)
print("IS ELEMENT%4d IN SET B? " % x, end="")
if b.s_isin(x):
print("YES")
else:
print("NO")
print()
# Sprawdzenie testu na zbiór pusty
print("IS SET A EMPTY?")
if a.s_empty():
print("YES")
else:
print("NO")
print()
print("IS INTERSECTION OF A AND " +
"DIFFERENCE OF B AND A EMPTY?")
c.s_difference(b, a)
c.s_intersection(a, c)
if c.s_empty():
print("YES")
else:
print("NO")
print()
# Usuwamy zbiory
a.s_clear()
b.s_clear()
c.s_clear()
|
| Wynik: |
| A: -19 -13 -10 -1 5 6 9 11 14 SIZE OF A IS 9 B: -19 -17 -11 -10 -8 0 2 6 7 15 17 18 SIZE OF B IS 12 UNION OF A AND B: -19 -17 -13 -11 -10 -8 -1 0 2 5 6 7 9 11 14 15 17 18 SIZE OF UNION IS 18 INTERSECTION OF A AND B: -19 -10 6 SIZE OF INTERSECTION IS 3 DIFFERENCE OF A AND B: -13 -1 5 9 11 14 SIZE OF DIFFERENCE IS 6 IS:-19 -10 -1 5 6 9 SUBSET OF A? YES IS: -11 2 7 15 17 18 SUBSET OF A? NO FROM A WE REMOVE-3 -11 11 6 6 A: -19 -13 -10 -1 5 9 14 SIZE OF A IS 7 IS ELEMENT -2 IN SET B? NO IS ELEMENT 10 IN SET B? NO IS ELEMENT 19 IN SET B? NO IS ELEMENT -20 IN SET B? NO IS ELEMENT 9 IN SET B? NO IS ELEMENT -5 IN SET B? NO IS ELEMENT 18 IN SET B? YES IS ELEMENT 4 IN SET B? NO IS ELEMENT 3 IN SET B? NO IS ELEMENT 2 IN SET B? YES IS SET A EMPTY? NO IS INTERSECTION OF A AND DIFFERENCE OF B AND A EMPTY? YES |
![]() |
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.