1. Trang chủ
  2. » Luận Văn - Báo Cáo

cấu trúc dữ liệu và giải thuật đề tài cây đỏ đen red black tree

47 0 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Cây Đỏ Đen (Red Black Tree)
Tác giả Trần Thị Sao Mai, Lê Mỹ Duyên, Phạm Thị Khuyên
Người hướng dẫn Nguyễn Thị Giang Huyền
Trường học Học viện Ngân hàng
Chuyên ngành Cấu trúc dữ liệu và giải thuật
Thể loại Bài tiểu luận
Năm xuất bản 2023
Thành phố Hà Nội
Định dạng
Số trang 47
Dung lượng 1,89 MB

Cấu trúc

  • 1. Đ t v n đ ặt vấn đề ấn đề ề (0)
  • 2. Đ nh nghĩa và tính ch t ịnh nghĩa và tính chất ấn đề (0)
  • 3. C u trúc ấn đề (0)
  • 4. M t ột số đi m thú v (tham kh o) ểm thú vị (tham khảo) ịnh nghĩa và tính chất ảo) (0)
  • 1. Phép tìm ki m ếm (11)
  • 2. Phép quay (11)
  • 3. Thao tác thêm node (12)
  • 4. Thao tác xóa node trên cây đ đen ỏ đen (21)
  • 1. Thêm node (29)
  • 2. Xóa node (34)
  • TÀI LIỆU THAM KHẢO (47)

Nội dung

Định nghĩa và tính chấtCâ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à đỏ

Phép tìm ki m ế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 right, key) else return search (root -> left, key);

RBNode * search (RBnode * root, int key) {

RBnode * p=root; while (p!=null){ if (p->info==key)return p; if (p->inforight; else p=p->left;

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

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.

Thao tác thêm node

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.

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

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

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

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

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

Hình 8 P là node đen

→ 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

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

(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

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

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

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

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,

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.

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

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

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

→ Đổ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

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,

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

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

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

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

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

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

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

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)

Thao tác xóa node trên cây đ đen ỏ đen

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.

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

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.

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

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

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

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

 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

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

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):

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 26 S đen và 2 con của S màu đen

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

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 28 Minh họa xóa node

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

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

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

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

Hình 31 S màu đỏ Đổi màu P sang đỏ, S sang đen:

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

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

Thêm node

#include using namespace std;

#define COUNT 10 struct Node { int data;

// 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;

// 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;

Node* Root; bool ll = false; bool rr = false; bool lr = false; bool rl = false;

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 = 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 = X->parent if (Root != root) { if (root->color == root->right->color == 1) f = true;

// *** 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-

// *** 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) { 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;

// 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

// 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;

// Cha đỏ - chú đỏ root->color = root->parent->right->color = 0; if (root != Root) root->parent->color = 1;

} void Insert(int key) { if (Root == NULL) {

Root = new Node{ key, NULL, NULL, NULL, 0 };

Root = insertHelp(Root, key); if (Root->color == 1)

}; 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 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) { 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 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;

// 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;

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-

// *** 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; 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-

// Cha đỏ - chú đen (rr or rl) if (root->left != NULL && root->left-

>color == 1) rl = true; if (root->right != NULL && root->right-

// Cha đỏ - chú đỏ root->color = root->parent->left->color 0; if (root != Root) root->parent->color = 1;

} } else { if (root->parent->right == NULL || root-

// Cha đỏ - chú đen (ll or lr) if (root->left != NULL && root->left-

>color == 1) ll = true; if (root->right != NULL && root->right-

// Cha đỏ - chú đỏ root->color = root->parent->right->color

= 0; if (root != Root) root->parent->color = 1;

} void Insert(int key) { if (Root == NULL) {

Root = new Node{ key, NULL, NULL, NULL, 0 };

Root = insertHelp(Root, key); if (Root->color == 1)

} } void fixDoubleBlack(Node* root) { if (root == Root) return;

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; 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;

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) uReplace = vDelete->right; else uReplace = NULL; bool uvBlack = ((uReplace == NULL) || (uReplace->color = 0)) && (vDelete->color == 0);

Node* sib = sibling(vDelete); if (uReplace == NULL) { if (vDelete == Root) {

} else { if (uvBlack) fixDoubleBlack(vDelete); else if(sib != NULL) sib->color = 1; if (vDelete->parent->left == vDelete) par->left = NULL; else par->right = NULL;

} 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;

} swapValues(uReplace, vDelete); deleteNode(uReplace);

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;

Node* vDelete = search(val); if (vDelete == NULL) { cout

Ngày đăng: 29/04/2024, 16:17

HÌNH ẢNH LIÊN QUAN

Hình 5. Sơ đồ phả hệ - cấu trúc dữ liệu và giải thuật đề tài cây đỏ đen red black tree
i ̀nh 5. Sơ đồ phả hệ (Trang 12)

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w