You are on page 1of 40

HỌC VIỆN NGÂN HÀNG

KHOA HỆ THỐNG THÔNG TIN QUẢN LÝ

Học phần: Cấu Trúc Dữ Liệu Và Giải Thuật

ĐỀ TÀI:

CÂY ĐỎ ĐEN (RED BLACK TREE)

Giảng viên hướng dẫn: Nguyễn Thị Giang Huyền

Sinh viên thực hiện: 24A4043246 - Trần Thị Sao Mai


24A4043247 - Lê Mỹ Duyên
24A4043251 - Phạm Thị Khuyên
Lớp: J03HTA

Hà Nội, ngày 30 tháng 06 năm 2023


DANH SÁCH THÀNH VIÊN NHÓM 3

STT HỌ VÀ TÊN MÃ SINH VIÊN % ĐÓNG GÓP

1 Lê Mỹ Duyên 24A4043247 33,4%

2 Trần Thị Sao Mai 24A4043246 33,3%

3 Phạm Thị Khuyên 24A4043251 33,3%


LỜI CẢM ƠN

Không có thành công nào mà không có sự hỗ trợ, dìu dắt dù ít hay nhiều, dù
trực tiếp hay gián tiếp của mọi người xung quanh bởi đơn giản một bàn tay không thể
vỗ thành tiếng. Với lòng biết ơn sâu sắc của mình, chúng em xin được gửi lời cảm ơn
tới toàn bộ quý thầy cô đã đồng hành cùng chúng em cũng như các thành viên, thầy cô
đã truyền đạt vốn tri thức quý giá của mình bằng lòng nhiệt thành và tâm huyết nhất
trong thời gian học tập vừa qua. Đặc biệt chúng em cũng xin cảm ơn Khoa hệ thống
thông tin quản lý định hướng Nhật Bản đã cho chúng em có cơ hội được tiếp cận với
môn học thật sự cần thiết và hữu ích, đó là môn “Cấu trúc dữ liệu và giải thuật”.
Chúng em xin được cảm ơn Cô Nguyễn Thị Giang Huyền đã luôn nhiệt huyết, tận tâm
hướng dẫn, giải đáp những khúc mắc cho chúng em cũng như các bạn trong lớp, nếu
không có những hướng dẫn chi tiết tận tình của cô thì có lẽ chúng em cũng không thể
hoàn thành bài báo cáo này.
Trong quá trình làm bài tập lớn không thể tránh được những thiếu sót, chúng
em rất mong mình có thể nhận được những ý kiến đóng góp của cô cũng như của các
bạn trong lớp để ngày một hoàn thiện bản thân mình hơn.
Sau cùng chúng em xin kính chúc các thầy cô trong khoa nói chung và Cô
Nguyễn Thị Giang Huyền nói riêng luôn mạnh khỏe, hạnh phúc để có thể tiếp tục
giảng dạy và công tác ở Học Viện, và truyền bá những kiến thức bổ ích cho chúng em
cũng như là các thế hệ sau này.
Chúng em xin được cảm ơn.

Nhóm sinh viên thực hiện


Nhóm 3
LỜI CAM ĐOAN

Chúng em xin được cam đoan rằng, bài tiểu luận trên là công sức và chất xám
của Nhóm 3 bỏ ra trong thời gian vừa qua. Việc một số mục có sự tham khảo về kiến
thức nghiệp vụ chung là trung thực, chính xác. Chúng em xin được chịu trách nhiệm
về lời cam đoan này cũng như đảm bảo tính liêm chính trong học thuật.

Nhóm sinh viên thực hiện


Nhóm 3
Mục lục
DANH MỤC HÌNH ẢNH..........................................................................................................................1
PHẦN I: GIỚI THIỆU..............................................................................................................................2
1. Đặt vấn đề................................................................................................................................................. 2
2. Định nghĩa và tính chất........................................................................................................................ 2
3. Cấu trúc...................................................................................................................................................... 4
4. Một số điểm thú vị (tham khảo)........................................................................................................ 4
PHẦN 2: CÁC THAO TÁC TRÊN CÂY ĐỎ ĐEN.................................................................................5
1. Phép tìm kiếm......................................................................................................................................... 5
2. Phép quay................................................................................................................................................. 5
3. Thao tác thêm node............................................................................................................................... 6
a, Các bước tiến hành................................................................................................................................ 6
b, Các trường hợp xảy ra nếu thêm node........................................................................................... 6
4. Thao tác xóa node trên cây đỏ đen................................................................................................ 13
a, Các bước tiến hành.............................................................................................................................. 13
b, Các TH có thể xảy ra nếu xóa node X của cây đỏ đen...............................................................13
1. Thêm node............................................................................................................................................... 18
2. Xóa node.................................................................................................................................................. 23
PHẦN 4: ỨNG DỤNG...........................................................................................................................34
PHẦN 5: TỔNG KẾT............................................................................................................................35
TÀI LIỆU THAM KHẢO...................................................................................................................36
DANH MỤC HÌNH ẢNH
Hình 2 . Một ví dụ về cây đỏ đen..............................................................................................1
Hình 3 . Trường hợp 3 node đen liền nhau..............................................................................1
Hình 4 . Chiều cao đen.............................................................................................................1
Hình 6 . Sơ đồ phả hệ...............................................................................................................1
Hình 7 . Các trường hợp thêm node.........................................................................................1
Hình 9 . P là node đen..............................................................................................................1
Hình 10 . Cả P và U đều đỏ......................................................................................................1
Hình 13 . Trường hợp Left–Left................................................................................................1
Hình 15 . Trường hợp Right–Right...........................................................................................1
Hình 16 . Trường hợp Right–Right...........................................................................................1
Hình 17 . Trường hợp Left–Right..............................................................................................1
Hình 19 . Trường hợp Right–Left..............................................................................................1
Hình 20 . Trường hợp Right–Left..............................................................................................1
Hình 21 . Trường hợp Right–Left..............................................................................................1
Hình 26 . Hai con của X (kể cả node NIL) đều là node đen......................................................1
Hình 30 . S màu đen và con trái của S màu đỏ, con phải S màu đen......................................1
Hình 32 . S màu đỏ...................................................................................................................1
Hình 33 . S màu đỏ...................................................................................................................1

1
PHẦN I: GIỚI THIỆU
1. Đặt vấn đề
Cây tìm kiếm nhị phân là một cấu trúc lưu trữ dữ liệu tốt với tốc độ tìm kiếm
nhanh. Tuy nhiên trong một số trường hợp cây tìm kiếm nhị phân có một số hạn chế.

Hình Hình
1. Các1.node
Các node
đượcđược
chèn chèn
theo thứ
theotựthứ
giảm
tự giảm
dần dần

Những node này tự sắp xếp thành một đường không phân nhánh.
Độ phức tạp: Khi cây một nhánh, sẽ trở thành một danh sách liên kết, dữ liệu sẽ
là một chiều thay vì hai chiều. Trong trường hợp này, thời gian truy xuất giảm về
O(N), thay vì O(log2N) đối với cây cân bằng.
Để đảm bảo thời gian truy xuất nhanh của cây, chúng ta cần phải bảo đảm cây
luôn luôn cân bằng (ít ra cũng là cây gần cân bằng).
Từ đó cây nhị phân tự cân bằng ra đời và có 2 cây tự cân bằng ra đời là cây
AVL và cây đỏ đen.
Cây AVL đã là BST tự cân bằng được phát minh vào năm 1962. Vậy thì tại sao
năm 1972 lại phải tạo ra thêm cây đỏ đen (RBTree) làm gì nữa? Đúng là sự cân bằng
của cây AVL thuộc dạng hoàn hảo khi chênh lệch về chiều cao của 2 cây con trái phải
luôn luôn nhỏ hơn hoặc bằng 1. Tuy nhiên, không phải khi nào hoàn hảo cũng tốt. Khi
ta thêm rất nhiều Node vào cây thì sẽ khiến cây phải quay (cân bằng) liên tục. Cây có
càng nhiều phần tử thì việc cân bằng lại cây sẽ càng mất công hơn. Cây đỏ đen sẽ khắc
phục yếu điểm này.

2. Định nghĩa và tính chất


Cây đỏ đen là một cây nhị phân tìm kiếm (BST) tuân thủ các quy tắc sau:
Mọi node phải là đỏ hoặc đen.
Node gốc và các nốt lá (NIL) phải luôn luôn đen.
Nếu một node là đỏ thì những node con của nó phải đen
 Cha node đỏ là đen; không thể có hai node đỏ cùng một lúc, nhưng 2 node
đen cùng một lúc thì có
Mọi đường dẫn từ gốc đến một lá phải có cùng số lượng node đen - Chiều cao
đen. Từ đó suy ra trong các đường đi từ gốc tới các lá đường đi dài nhất không vượt
quá hai lần đường đi ngắn nhất. Do đó cây đỏ đen là gần cân bằng.
2
Khi chèn hay xóa một node mới, cần phải tuân thủ các quy tắc trên - quy tắc đỏ
đen. Nếu được tuân thủ, cây sẽ được cân bằng.

Hình 1. Một ví dụ về cây đỏ đen

Trường hợp có 3 node đen liên tiếp:

Hình 2. Trường hợp 3 node đen liền nhau

Ở đây mình có một cây đỏ đen (nhìn khá cân bằng), có thể thấy từ node root
đến node NULL đầu tiên có 3 node đen là 12, 10, null. Nhưng từ node root đến node
NULL thứ ba thì chỉ có 2 node đen là 12 và null. Như vậy thì đã vi phạm quy tắc số 4.
(Theo quy tắc số 4: Mọi đường dẫn từ một node đến bất kì node NULL (thuộc con của
nó) thì đều có cùng số lượng node đen).

3
Vì vậy, không thể có 3 node đen liên tiếp. Vì thế số lượng node đen từ root đến
tất cả các node NULL luôn luôn bằng nhau. Sự khác biệt giữa các đường đi là các
node đỏ, tuy nhiên vẫn không đáng kể để ảnh hưởng đến sự cân bằng của cây.

3. Cấu trúc
enum COLOR
{
RED, BLACK
};
struct RBNode
{
int Infor;
RBNode* Left;
RBNode* Right;
RBNode* Parent;
COLOR Color;
};

4. Một số điểm thú vị (tham khảo)

Hình 3. Chiều cao đen

Chiều cao đen: là số lượng node đen từ root → NULL. Vì thế nếu cây đỏ đen
có chiều cao là h thì có chiều cao đen >= h / 2.
Chiều cao cây đỏ đen có n node là h thì: h <= 2 * log2(n + 1).
Độ sâu đen của một node là số lượng node đen từ node đó → NULL. (Khá
tương tự chiều cao đen).
Mỗi cây đỏ đen đều là một trường hợp đặc biệt của cây tìm kiếm nhị phân BST.

4
PHẦN 2: CÁC THAO TÁC TRÊN CÂY ĐỎ ĐEN
1. Phép tìm kiếm
Thực hiện tương tự như phép tìm kiếm trong cây nhị phân theo 2 cách: Đệ quy
hoặc Không đệ quy.
Đệ quy:
RBNode *search (RBNode * root, int key)
{
if (root =null)
return null;
if (root ->info==key)
return root;
if (root->info<key)
return search (root -> right, key)
else
return search (root -> left, key);
}
Không đệ quy:
RBNode * search (RBnode * root, int key)
{
RBnode * p=root;
while (p!=null){
if (p->info==key)return p;
if (p->info<key)
p=p->right;
else
p=p->left;
}
}

2. Phép quay
Thực ra quay không có nghĩa là các node bị quay mà để chỉ sự thay đổi quan hệ
giữa chúng. Một node được chọn làm "đỉnh" của phép quay. Nếu chúng ta đang thực
hiện một phép quay qua phải, node "đỉnh" này sẽ di chuyển xuống dưới và về bên
phải, vào vị trí của node con bên phải của nó. Node con bên trái sẽ đi lên để chiếm lấy
vị trí của nó.

Hình 4. Phép quay

5
Phải đảm bảo trong phép quay phải, node ở đỉnh phải có node con trái. Nếu
không chẳng có gì để quay vào điểm đỉnh. Tương tự, nếu làm phép quay trái, node ở
đỉnh phải có node con phải.

3. Thao tác thêm node


a, Các bước tiến hành
Việc thực hiện chèn một node N vào cây đỏ đen sẽ được thực hiện theo các
bước sau đây:
B1: Gán màu của Node cần chèn là màu đỏ.
B2: Thực hiện chèn một node vào cây đỏ đen giống như thao tác chèn trên cây
nhị phân tìm kiếm (nếu cây rỗng thêm N thì N là gốc, cây khác rỗng → kiểm tra xem
lớn hay nhỏ hơn gốc: nhỏ → trái, lớn → phải).
B3: Điều chỉnh lại nếu thêm mới vi phạm các qui định của cây đỏ đen.

Một số qui ước:

Hình 5. Sơ đồ phả hệ

N: Node vừa được thêm vào cây.


P: Node cha của N.
U: Node chú bác của N (node cùng cha với P).
G: Node cha của nút P (node ông của P).

b, Các trường hợp xảy ra nếu thêm node


TH1: N được chèn vào vị trí node gốc của cây. N → N là gốc. Nếu N không là
gốc thì: N có P. Khi đó dẫn đến TH2.
TH2: P là node đen, nếu P không đen thì dẫn đến TH3.
TH3: Cả P và U đều đỏ.
TH4: P là node đỏ, U là node đen.

6
Hình 6. Các trường hợp thêm node

TH1: N được chèn vào vị trí node gốc của cây


Nút chèn là nút đỏ → vi phạm yêu cầu: nút gốc phải là nút đen → đổi màu nút
N thành màu đen.

Hình 7. Trường hợp N được chèn là node gốc

TH2: P là node đen

Hình 8. P là node đen

7
→ Không vi phạm định nghĩa cây đỏ đen.
→ Không vi phạm tính chất của cây đỏ đen.
→ Không cần điều chỉnh.

TH3: Cả P và U đều đỏ

Hình 9. Cả P và U đều đỏ

→ Vi phạm yêu cầu: cha của nút đỏ phải là nút đen.


→ Chuyển P và U thành node đen (cả 2 con node đỏ phải là đen)
(đường đi của G và U chỉ có 1 đen → tăng 2 nút đen → dư 1 đen).

Hình 10. Cả P và U đều đỏ


→ Chuyển G thành node đỏ
(có thể dẫn đến dây chuyền vi phạm → xét tiếp).

VD: Tạo cây đỏ đen từ dãy số sau: 50, 75, 25, 80, 100, 110, 105

Hình 11. Minh họa thêm node


TH4: P là node đỏ, U là node đen
P là con trái của G, N là con trái của P (Left - Left).
P là con phải của G, N là con phải của P (Right - Right).
P là con trái của G, N là con phải của P (Left - Right).
P là con phải của G, N là con trái của P (Right - Left).

TH4.1. P là con trái của G, N là con trái của P (Left – Left): P đỏ, U đen, P trái G,
N trái P

Hình 12. Trường hợp Left–Left

→ Vi phạm yêu cầu: cha nút đỏ phải là nút đen.


→ Quay phải node G.
→ Đổi màu node G và P: P thành đen, G thành đỏ (đảm bảo chiều cao đen).

Hình 13. Trường hợp Left–Left

9
TH4.2. P là con phải của G, N là con phải của P(Right - Right): P đỏ, U đen, P phải
G, N phải P

Hình 14. Trường hợp Right–Right

→ Vi phạm yêu cầu: cha nút đỏ phải là nút đen.


→ Quay trái node G.
→ Đổi màu node G và P: P thành đen, G thành đỏ (đảm bảo chiều cao đen).

Hình 15. Trường hợp Right–Right

TH4.3. P là con trái của G, N là con phải của P(Left - Right): P đỏ, U đen, P trái G,
N phải P
→ Vi phạm yêu cầu: cha nút đỏ phải là nút đen.
→ Quay trái node P.

10
Hình 16. Trường hợp Left–Right

→ Thực hiện như L - L.


→ Quay phải node G.
→ Đổi màu node G và N: N thành đen, G thành đỏ (đảm bảo chiều cao đen).

Hình 17. Trường hợp Left–Right

TH4.4. P là con phải của G, N là con trái của P (Right - Left): P đỏ, U đen, P phải
G, N trái P

Hình 18. Trường hợp Right–Left

11
→ Vi phạm yêu cầu: cha nút đỏ phải là nút đen.
→ Quay phải node P.
→ Thực hiện như R - R.
→ Quay trái node G.

Hình 19. Trường hợp Right–Left

→ Đổi màu node G và N: N thành đen, G thành đỏ (đảm bảo chiều cao đen).

Hình 20. Trường hợp Right–Left

VD: Tạo cây đỏ đen từ dãy số sau: 50, 75, 25, 80, 100, 110, 105 (tiếp tục với 100)

Hình 21. Minh họa thêm node

12
4. Thao tác xóa node trên cây đỏ đen
a, Các bước tiến hành
B1: Tìm kiếm node cần xóa, nếu không tìm thấy thì dừng.
B2: Nếu tìm thấy, ta tiến hành xóa.
Node cần xóa là nút lá.
Node cần xóa là nút 1 con: Nối con trỏ trỏ vào nút cần xóa tới thẳng con
của nút cần xóa.
Node cần xóa là nút 2 con (tìm node thay thế, thường là nút lớn nhất của
con bên trái).
B3: Điều chỉnh lại nếu vi phạm các quy định của cây đỏ đen.
b, Các TH có thể xảy ra nếu xóa node X của cây đỏ đen
TH1: Node cần xóa X là node đỏ hoặc node gốc
Việc xóa node X sẽ không ảnh hưởng tới đặc điểm và tính chất của cây đỏ đen nên
không cần điều chỉnh.
Nếu xóa node bên phải thì duyệt đến khi node con bên trai là lá thì lấy lá thế chỗ
cho node xóa.

Hình 23. Xóa node đỏ Hình 22. Xóa node gốc

TH2: Node cần xóa X là node đen:


TH2.1. Node con của X là nút đỏ (có 1 con):
Sau khi xóa X thì nối P với con của X (Y)
Điều chỉnh màu của node con của X thành màu đen

Hình 24. Node con của X là nút đỏ (có 1 con)

13
TH2.2. Hai con của X (kể cả node NIL) đều là node đen:
Gọi S là node anh em của X: Có 4 trường hợp xảy ra:
 S màu đen và 2 con của S màu đen
 S màu đen và con phải của S màu đỏ
 S màu đen và con trái của S màu đỏ, con phải S màu đen
 S màu đỏ

Hình 25. Hai con của X (kể cả node NIL) đều là node đen

Tất cả các đường đi qua nút X sẽ bị ít hơn 1 nút đen


→ Y được gọi là nút 2 đen (đen kép)

TH2.2.1. S màu đen và 2 con của S màu đen:


Để đảm bảo định nghĩa, tính chất của cây đỏ đen
Đổi nút S sang màu đỏ, Đổi nút P sang màu đen

Hình 26. S đen và 2 con của S màu đen

TH2.2.2. S màu đen và con phải của S màu đỏ (con trái màu gì cũng được):
14
Quay trái tại P
Sau đó tiến hành đảo màu của P và S: P màu gì S màu đó, Z đổi màu đen

Hình 27. S màu đen và con phải của S màu đỏ

VD: Xóa node đỏ 80

Hình 28. Minh họa xóa node


TH2.2.3. S màu đen và con trái của S màu đỏ, con phải của S màu đen:
Ta tiến hành quay phải tại S
Đổi màu Z và S

Hình 29. S màu đen và con trái của S màu đỏ, con phải S màu đen

15
Sau khi đổi màu, trở lại trường hợp trước đó: S màu đen và con phải của S màu đỏ
Quay trái tại P và tiến hành đảo màu

Hình 30. S màu đen và con trái của S màu đỏ, con phải S màu đen

TH2.2.4. S màu đỏ:


Tiến hành quay trái tại P

Hình 31. S màu đỏ

Đổi màu P sang đỏ, S sang đen:

Hình 32. S màu đỏ

Y vẫn là nút đen kép, tùy từng cấu trúc của cây xem xem nó rơi vào trường hợp nào
trong các TH rồi tiến hành tương tự.
16
VD: Xóa node gốc
Khi xóa 50, tiến hành đổi chỗ 25 và 50

Hình 33. Minh họa xóa node

Hình 34. Minh họa xóa node

PHẦN 3: THUẬT TOÁN CÀI ĐẶT


1. Thêm node
#include <iostream>

17
#include <cmath>

using namespace std;


#define COUNT 10

struct Node {
int data;
Node* left;
Node* right;
Node* parent;
bool color;
//1 -> Red | 0 -> Black
};

Node* rotateRight(Node* root) {


Node* x = root->left;
// Gán x->right vào left root
root->left = x->right;
if (x->right != NULL)
x->right->parent = root;

// Gán root vào x.right


x->right = root;
root->parent = x;

// Trả về x
return x;
}

Node* rotateLeft(Node* root) {


Node* y = root->right;
// Gán y->left vào right root
root->right = y->left;
if (y->left != NULL)
y->left->parent = root;

// Gán root vào y.left


y->left = root;
root->parent = y;

// Trả về y;
return y;
}

struct RedBlackTree {
Node* Root;
bool ll = false;
18
bool rr = false;
bool lr = false;
bool rl = false;
RedBlackTree() {
Root = NULL;
}
Node* insertHelp(Node* root, int key) {
// f đúng khi có xung đột RED RED
bool f = false;

if (root == NULL) {
return new Node{ key, NULL, NULL, NULL, 1 }; // RED Node
}
else if (key < root->data) {
root->left = insertHelp(root->left, key);
root->left->parent = root;
// root->left = Node X
// root = X->parent
if (Root != root) {
if (root->color == root->left->color == 1)
f = true;
}
}
else {
root->right = insertHelp(root->right, key);
root->right->parent = root;
// root->right = Node X
// root = X->parent
if (Root != root) {
if (root->color == root->right->color == 1)
f = true;
}
}

// Xử lý 4 TH lệch
// *** Khi này (ll, lr, rr, rl = false) nên chưa xử lí liền
// *** Sau khi thoát 1 vòng đệ quy thì: root = X->parent->parent
// *** Tức là Node ông, lúc này ta quay Node ông
// Case 1 : Left left - Trái trái
if (ll) {
root = rotateRight(root);// Quay phải tại nút gốc
root->color = 0; // Chuyển nút gốc thành Black
root->right->color = 1; // Đổi màu con phải nút gốc thành Red
ll = false;
}
// Case 2 : Right right - Phải phải
else if (rr) {
19
root = rotateLeft(root); // Quay phải tại nút gốc
root->color = 0; // Đổi màu nút gốc thành Black
root->left->color = 1; // Đổi màu bên trái nút gốc thành Red
rr = false;
}
// Case 3 : Left right - Phải trái
else if (lr) {
root->left = rotateLeft(root->left);// Quay trái tại nút bên trái
gốc
root->left->parent = root;
root = rotateRight(root); // Quay phải nút gốc
root->color = 0; // Đổi màu nút gốc thành Black
root->right->color = 1; // Đổi màu bên phải nút gốc thành đỏ
lr = false;
}
// Case 4 : Right left - Phải trái
else if (rl) {
root->right = rotateRight(root->right);
root->right->parent = root;

root = rotateLeft(root);
root->color = 0;
root->left->color = 1;
rl = false;
}

// Xử lí xung đột đỏ - RED RED


if (f) {
if (root->parent->right == root) {
if (root->parent->left == NULL || root->parent->left->color == 0) {
// Cha đỏ - chú đen (rr or rl)
if (root->left != NULL && root->left->color == 1)
rl = true;
if (root->right != NULL && root->right->color == 1)
rr = true;
}
else {
// Cha đỏ - chú đỏ
root->color = root->parent->left->color = 0;
if (root != Root)
root->parent->color = 1;
}
}
else {
if (root->parent->right == NULL || root->parent->right->color == 0){
// Cha đỏ - chú đen (ll or lr)
if (root->left != NULL && root->left->color == 1)
20
ll = true;
if (root->right != NULL && root->right->color == 1)
lr = true;
}
else {
// Cha đỏ - chú đỏ
root->color = root->parent->right->color = 0;
if (root != Root)
root->parent->color = 1;
}
}
f = false;
}
return root;
}

void Insert(int key) {


if (Root == NULL) {
Root = new Node{ key, NULL, NULL, NULL, 0 };
}
else {
Root = insertHelp(Root, key);
if (Root->color == 1)
Root->color = 0;
}
}
};

string getColor(Node* root) {


if (root->color == 1)
return "RED";
return "BLACK";
}

// In - Print 2D ra console
void print2DUtil(Node* root, int space) {
if (root == NULL)
return;
space += COUNT;

print2DUtil(root->right, space);
cout << endl;

for (int i = COUNT; i < space; i++)


cout << " ";
cout << root->data << " (" << getColor(root) << ") " << "\n";

21
print2DUtil(root->left, space);
}

void print2D(Node* root) {


print2DUtil(root, 0);
}

int main() {
RedBlackTree RBTree;
RBTree.Insert(1);
RBTree.Insert(4);
RBTree.Insert(6);
RBTree.Insert(3);
RBTree.Insert(5);
RBTree.Insert(7);
RBTree.Insert(8);
RBTree.Insert(2);
RBTree.Insert(9);

print2D(RBTree.Root);
return 0;
}

Kết quả:

Hình 35. Kết quả thêm node


2. Xóa node
#include <iostream>
#include <cmath>

22
using namespace std;
#define COUNT 10

struct Node {
int data;
Node* left;
Node* right;
Node* parent;
bool color;
//1 -> Red | 0 -> Black
};

Node* maxValueNode(Node* root)


{
Node* current = root;

// Tìm kiếm Node có giá trị lớn nhất


while (current->right != NULL)
current = current->right;

return current;
}

Node* sibling(Node* current) {


if (current->parent == NULL)
return NULL;
if (current->parent->left == current)
return current->parent->right;
return current->parent->left;
}

void swapColors(Node* x1, Node* x2) {


bool temp;
temp = x1->color;
x1->color = x2->color;
x2->color = temp;
}

void swapValues(Node* u, Node* v) {


int temp;
temp = u->data;
u->data = v->data;
v->data = temp;
}

bool hasRedChild(Node* x) {
23
if (x->right != NULL)
if (x->right->color == 1)
return true;
if (x->left != NULL)
if (x->left->color == 1)
return true;
return false;
}

string getColor(Node* root) {


if (root->color == 1)
return "RED";
return "BLACK";
}

// In - Print 2D ra console
void print2DUtil(Node* root, int space) {
if (root == NULL)
return;
space += COUNT;

print2DUtil(root->right, space);
cout << endl;

for (int i = COUNT; i < space; i++)


cout << " ";
cout << root->data << " (" << getColor(root) << ") " << "\n";
print2DUtil(root->left, space);
}

void print2D(Node* root) {


print2DUtil(root, 0);
}

struct RedBlackTree {
Node* Root;
bool ll = false;
bool rr = false;
bool lr = false;
bool rl = false;
RedBlackTree() {
Root = NULL;
}
Node* rotateRight(Node* root) {
Node* x = root->left;
// Gán x->right vào left root
root->left = x->right;
24
if (x->right != NULL)
x->right->parent = root;

x->parent = root->parent;
if (root->parent == NULL)
Root = x;
else if (root->parent->left == root)
root->parent->left = x;
else
root->parent->right = x;
// Gán root vào x.right
x->right = root;
root->parent = x;

// Trả về x
return x;
}

Node* rotateLeft(Node* root) {


Node* y = root->right;
// Gán y->left vào right root
root->right = y->left;
if (y->left != NULL)
y->left->parent = root;

y->parent = root->parent;
if (root->parent == NULL)
Root = y;
else if (root->parent->left == root)
root->parent->left = y;
else
root->parent->right = y;

// Gán root vào y.left


y->left = root;
root->parent = y;

// Trả về y;
return y;
}
Node* insertHelp(Node* root, int key) {
// f đúng khi có xung đột RED RED
bool f = false;

if (root == NULL) {
return new Node{ key, NULL, NULL, NULL, 1 }; // RED Node
}
25
else if (key < root->data) {
root->left = insertHelp(root->left, key);
root->left->parent = root;
// root->left = Node X
// root = X->parent
if (Root != root) {
if (root->color == root->left->color == 1)
f = true;
}
}
else {
root->right = insertHelp(root->right, key);
root->right->parent = root;
// root->right = Node X
// root = X->parent
if (Root != root) {
if (root->color == root->right->color == 1)
f = true;
}
}

// Xử lý 4 TH lệch
// *** Khi này (ll, lr, rr, rl = false) nên chưa xử lí liền
// *** Sau khi thoát 1 vòng đệ quy thì: root = X->parent-
>parent
// *** Tức là Node ông, lúc này ta quay Node ông
// Case 1 : Left left - Trái trái
if (ll) {
root = rotateRight(root);
root->color = 0;
root->right->color = 1;
ll = false;
}
// Case 2 : Right right - Phải phải
else if (rr) {
root = rotateLeft(root);
root->color = 0;
root->left->color = 1;
rr = false;
}
// Case 3 : Left right - Phải trái
else if (lr) {
root->left = rotateLeft(root->left);
root->left->parent = root;

root = rotateRight(root);
root->color = 0;
26
root->right->color = 1;
lr = false;
}
// Case 4 : Right left - Phải trái
else if (rl) {
root->right = rotateRight(root->right);
root->right->parent = root;

root = rotateLeft(root);
root->color = 0;
root->left->color = 1;
rl = false;
}

// Xử lí xung đột đỏ - RED RED


if (f) {
if (root->parent->right == root) {
if (root->parent->left == NULL || root->parent-
>left->color == 0) {
// Cha đỏ - chú đen (rr or rl)
if (root->left != NULL && root->left->color
== 1)
rl = true;
if (root->right != NULL && root->right->color
== 1)
rr = true;
}
else {
// Cha đỏ - chú đỏ
root->color = root->parent->left->color = 0;
if (root != Root)
root->parent->color = 1;
}
}
else {
if (root->parent->right == NULL || root->parent-
>right->color == 0) {
// Cha đỏ - chú đen (ll or lr)
if (root->left != NULL && root->left->color
== 1)
ll = true;
if (root->right != NULL && root->right->color
== 1)
lr = true;
}
else {
// Cha đỏ - chú đỏ
27
root->color = root->parent->right->color = 0;
if (root != Root)
root->parent->color = 1;
}
}
f = false;
}
return root;
}

void Insert(int key) {


if (Root == NULL) {
Root = new Node{ key, NULL, NULL, NULL, 0 };
}
else {
Root = insertHelp(Root, key);
if (Root->color == 1)
Root->color = 0;
}
}
void fixDoubleBlack(Node* root) {
if (root == Root)
return;
Node* sib = sibling(root);
Node* par = root->parent;

if (sib == NULL)
fixDoubleBlack(par);
else {
if (sib->color == 1) {
par->color = 1;
sib->color = 0;

if (sib->parent->left == sib)
par = rotateRight(par);
else
par = rotateLeft(par);

fixDoubleBlack(root);
}
else {
if (hasRedChild(sib)) {
if (sib->parent->left == sib) {
if (sib->left != NULL && sib->left-
>color) {
sib->left->color = sib->color;
sib->color = par->color;
28
par->color = 0;

par = rotateRight(par);
}
else {
sib->right->color = par->color;
par->color = 0;
sib = rotateLeft(sib);
par = rotateRight(par);
}
}
else {
if (sib->right != NULL && sib->right-
>color) {
sib->right->color = sib->color;
sib->color = par->color;
par->color = 0;

par = rotateLeft(par);
}
else {
sib->left->color = par->color;
par->color = 0;
sib = rotateRight(sib);
par = rotateLeft(par);
}
}
}
else {
sib->color = 1;
if (par->color == 0)
fixDoubleBlack(par);
else
par->color = 0;
}
}
}

}
void deleteNode(Node* vDelete) {
Node* uReplace;

if ((vDelete->left != NULL) && (vDelete->right != NULL))


uReplace = maxValueNode(vDelete->left);
else if (vDelete->left != NULL)
uReplace = vDelete->left;
else if (vDelete->right != NULL)
29
uReplace = vDelete->right;
else
uReplace = NULL;

bool uvBlack = ((uReplace == NULL) || (uReplace->color == 0))


&& (vDelete->color == 0);
Node* par = vDelete->parent;
Node* sib = sibling(vDelete);
if (uReplace == NULL) {
if (vDelete == Root) {
Root = NULL;
}
else {
if (uvBlack)
fixDoubleBlack(vDelete);
else if(sib != NULL)
sib->color = 1;

if (vDelete->parent->left == vDelete)
par->left = NULL;
else
par->right = NULL;
}
delete vDelete;
return;
}

if (vDelete->left == NULL || vDelete->right == NULL) {


if (vDelete == Root) {
vDelete->data = uReplace->data;
vDelete->left = vDelete->right = NULL;
delete uReplace;
}
else {
if (vDelete->parent->left == vDelete)
par->left = uReplace;
else
par->right = uReplace;
delete vDelete;

uReplace->parent = par;
if (uvBlack)
fixDoubleBlack(uReplace);
else
uReplace->color = 0;
}
return;
30
}
swapValues(uReplace, vDelete);
deleteNode(uReplace);
}
Node* search(int val) {
Node* temp = Root;
while (temp != NULL) {
if (val < temp->data) {
if (temp->left == NULL)
return NULL;
else
temp = temp->left;
}
else if (val == temp->data) {
break;
}
else {
if (temp->right == NULL)
return NULL;
else
temp = temp->right;
}
}
return temp;
}
void Delete(int val) {
Node* vDelete = search(val);
if (vDelete == NULL) {
cout << "\n ** Khong tim thay Node can xoa **\n";
return;
}
else {
deleteNode(vDelete);
}
return;
}
};

int main() {
RedBlackTree RBTree;
RBTree.Insert(1);
RBTree.Insert(4);
RBTree.Insert(6);
RBTree.Insert(3);
RBTree.Insert(5);
RBTree.Insert(7);
RBTree.Insert(8);
31
RBTree.Insert(2);
RBTree.Insert(9);

print2D(RBTree.Root);
cout << "\n---------------------------\n";
RBTree.Delete(5);
print2D(RBTree.Root);
return 0;
}

Kết quả:

Hình 36. Kết quả xóa node

32
PHẦN 4: ỨNG DỤNG
Một ứng dụng của cây đỏ đen – Red Black Tree:
Hầu hết các chức năng của thư viện cây BST tự cân bằng trong C++ (hoặc
TreeSet và TreeMap trong Java) đều sử dụng cấu trúc cây đỏ đen.
Lập lịch tiến trình CPU cho hệ điều hành Linux.
Áp dụng vào trong thuật toán phân cụm K-mean nhằm giảm độ phức tạp về thời
gian.
Ngoài ra MySQL cũng sử dụng cây đỏ đen cho các chỉ mục trên bảng

33
PHẦN 5: TỔNG KẾT
Ưu điểm:
Red Black Trees có độ phức tạp về thời gian được đảm bảo là O(log n) cho các
thao tác cơ bản như chèn, xóa và tìm kiếm.
Cây Đỏ Đen tự cân bằng.
Cây Đỏ Đen có thể được sử dụng trong nhiều ứng dụng do hiệu suất hiệu quả
và tính linh hoạt của chúng.
Cơ chế được sử dụng để duy trì sự cân bằng trong Cây Đỏ Đen tương đối đơn
giản và dễ hiểu.
Nhược điểm:
Red Black Trees yêu cầu thêm một bit lưu trữ cho mỗi nút để lưu trữ màu của
nút (đỏ hoặc đen).
Chi phí chèn và xóa cao hơn BST vì phải thực hiện chèn và đổi màu.

34
TÀI LIỆU THAM KHẢO

Phát, N. T., 2022. luyencode.net. [Trực tuyến]


Available at: https://blog.luyencode.net/cay-do-den-red-black-tree-phan-2-insert/#5-
code-chinh

Phát, N. T., 2022. luyencode.net. [Trực tuyến]


Available at: https://blog.luyencode.net/cay-do-den-red-black-tree-phan-3/

Vinhvv, 2022. [Trực tuyến]


Available at: https://www.youtube.com/watch?v=bLydJnSg8bA&t=1744s

35

You might also like