You are on page 1of 97

TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học

KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Cây Nhị Phân Tìm Kiếm


(Binary Search Tree)

Lecturer: Duc-Hieu Tran

Title: MSc. Computer Science


Nội dung

Giới thiệu

Cây nhị phân tìm kiếm

Các thao tác trên cây nhị phân tìm kiếm

17/05/2023 ThS. Trần Đức Hiếu 2


TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Nhắc lại…
Nhắc lại …
Danh sách liên kết
 Việc tìm kiếm phần tử trong danh sách là tìm kiếm tuần tự (Sequential
Search)
 Tìm kiếm bắt đầu từ phần tử đầu tiên của danh sách
Ví dụ: tìm phần tử trong danh sách có giá trị là ‘SV3’
node.data ==
‘SV3’
head node
→ Dừng tail
node node

SV1 SV2 SV3 SV4 NULL

17/05/2023 next next next next 4


Nhắc lại …
Danh sách liên kết
Nếu danh sách có n phần tử  thời gian tìm kiếm là T(n) = O(n)
Cần có một phương pháp tìm kiếm nhanh hơn  cấu trúc Cây Nhị Phân Tìm
Kiếm

17/05/2023 5
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Cây nhị phân tìm kiếm


(Binary Search Tree)
Giới thiệu
Các cấu trúc dữ liệu động như DSLK đơn, đôi, vòng,… có sự mềm
dẻo, linh hoạt, nhưng lại bị hạn chế trong việc tìm kiếm thông tin
(chỉ có thể tìm kiếm theo cách tuần tự)
Cấu trúc cây có thể khắc phục nhược điểm trên do tính chất phân
cấp của nó. Khi cần tìm kiếm thì đi từ gốc tới nhánh chứa thông tin
Tuy nhiên, cần có một số ràng buộc để việc tìm kiếm trên cây trở
nên chặt chẽ, dễ dùng hơn
Một cấu trúc như vậy gọi là cây nhị phân tìm kiếm
17/05/2023 7
Cây nhị phân tìm kiếm
44
Binary Search Tree (BST)

Cây nhị phân tìm kiếm


18 Nút 88
(CNPTK) là cây nhị phân mà
tại mọi nút của cây thì khóa của Khóa
13 37 59 108
nút này lớn hơn tất cả khóa
của cây con trái và nhỏ hơn 15 23 40 55 71
tất cả khóa của cây con phải

17/05/2023 8
Ví dụ
7 6

3 8
3 8 >

9 1 7 9
1 4

2 2

Hình a. cây nhị phân tìm kiếm Hình b. Không là cây nhị phân tìm
kiếm
17/05/2023 9
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Cấu trúc dữ liệu


(Data structure)
Nút
Cấu trúc dữ liệu của Node
key count

left right

Một nút của cây có các thuộc tính (attribute):


 key: chứa khóa của nút. Khóa của các nút trong 1 cây không được trùng nhau
 count: số lần xuất hiện của khóa trong cây. Nếu cùng 1 giá trị khóa được thêm
nhiều lần vào Cây thì chỉ có 1 nút chứa giá trị khóa này
 left: con trỏ đến nút con Trái
 right:
17/05/2023
con trỏ đến nút con Phải 11
Nút
Cấu trúc dữ liệu của Node
public class Node<E> {
// Thành phần dữ liệu
private E key;// khóa của nút
private int count;// Số lần xuất hiện của key trong cây

// Thành phần liên kết


private Node<E> left; // Con trỏ để liên kết tới Node con trái
private Node<E> right; // Con trỏ để liên kết tới Node con phải

// Thành phần xử lý
...

} 17/05/2023 12
Nút
Khởi tạo Node rỗng với khóa key
// Constructor của Node

public Node(E key) {


this.key = key;
this.count = 1;
this.left = null;
this.right = null;
} 17/05/2023 13
Cây Nhị Phân Tìm Kiếm
Cấu trúc dữ liệu của Cây NPTK
root

key count

left right

key count key count

left right left right

… … …

17/05/2023 NULL 14
Cây Nhị Phân Tìm Kiếm
Cấu trúc dữ liệu của Cây NPTK
Cây NPTK chỉ quản lý 1 nút gốc root
 root: con trỏ nút gốc của CNPTK
 Các nút lá của cây trỏ về null

17/05/2023 15
Cây
Cấu trúc dữ liệu của Cây
public class BinarySearchTree<E> {
// Thành phần dữ liệu
private Node<E> root;
}

17/05/2023 16
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Tính chất
Tính chất cây nhị phân tìm kiếm
Nhờ ràng buộc về khóa nên 44

việc tìm kiếm trên cây có định


hướng và nhanh đáng kể 18 88

Gọi n là số nút của cây thì


13 37 59 108
chi phí tìm kiếm trung bình là
O(log2n)
15 23 40 55 71

Vì sao ?
17/05/2023 18
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Các thao tác trên


Cây Nhị Phân Tìm Kiếm
Thao tác trên cây nhị phân tìm kiếm
Khởi tạo cây rỗng

Kiểm tra cây rỗng

Thêm khóa vào cây

Tìm kiếm khóa trong cây

Loại bỏ khóa trên cây

Duyệt cây

Giải phóng (hủy bỏ) cây


17/05/2023 20
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Khởi tạo cây rỗng


(Create empty BST)
Khởi tạo cây rỗng
Cây NPTK là rỗng (empty tree) khi root là null
// Thiết lập cây rỗng trong root
// phương thức khởi tạo
NULL
public BinarySearchTree() {
this.root = null;
}

17/05/2023 22
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Kiểm tra cây rỗng


(Check empty BST)
Kiểm tra cây rỗng
Nếu cây NPTK là rỗng (empty tree) thì root là null, ngược lại thì
khác rỗng root

// Phương thức kiểm tra cây rỗng


NULL
public boolean isEmpty() {
return (this.root == null);
}

17/05/2023 24
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Thêm khóa vào cây


(Insert to BST)
Thêm khóa vào cây
Phải đảm bảo điều kiện ràng buộc của CNPTK:

Con Trái < Cha < Con Phải


 Có thể thêm vào nhiều chỗ khác nhau, nhưng thêm vào nút lá là
tiện nhất
 Phải thực hiện quá trình tìm kiếm trước để xác định chỗ cần
thêm sau đó thì thêm phần tử mới vào

17/05/2023 26
Thêm khóa vào cây
 Giải thuật
Gọi khóa cần thêm vào là key

Thêm khóa vào CNPTK bao gồm 3 bước bắt đầu từ nút gốc root

Bước 1: Nếu root là null thì tạo nút mới node có khóa là key (node là nút lá). Kết
thúc thêm vào

Bước 2: Nếu khóa của root là key thì tăng số lần xuất hiện của khóa này. Kết thúc
thêm vào

Bước 3: Nếu khóa key nhỏ hơn khóa của root thì thêm khóa key vào cây con trái
của root; ngược lại, thêm khóa key vào cây con phải của root. Lặp lại bước 1
17/05/2023 27
Thêm khóa vào cây
Ví dụ: thêm khóa x = 50 vào một root
44
cây khác rỗng x > 44

18 88
x < 88

13 37 59 108
x < 59

15 23 40 55 71

x < 55
50
17/05/2023 28
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây root

vào một cây NPTK rỗng NULL

7 3 8 4 1 2 9 6 5

17/05/2023 29
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây root

vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5

17/05/2023 30
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 3root
<7

vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5
3

17/05/2023 31
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 8>7

vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5
3 8

17/05/2023 32
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 4<7
4>3
vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5
3 8

17/05/2023 33
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 1<7
1<3
vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5
3 8

4
1

17/05/2023 34
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 2<7
2<3
vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5 2>1
3 8

4
1

17/05/2023 35
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 9>7

vào một cây NPTK rỗng 9>8


7

7 3 8 4 1 2 9 6 5
3 8

4 9
1

17/05/2023 36
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 6<7
6>3
vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5
3 6>4
8

4 9
1

2 6

17/05/2023 37
Thêm khóa vào cây
Ví dụ: thêm các khóa dưới đây 5<7
5>3
vào một cây NPTK rỗng 7

7 3 8 4 1 2 9 6 5
3 5>4
8

5<6
4 9
1

2 6

17/05/2023 38
Thêm khóa vào cây
 Giải thuật (đệ qui)
Insert(<nút> root, <khóa> key) {
if (root là rỗng)
tạo nút lá mới root có khóa là key
else if (key < khóa của root)
Insert(rootcây con trái, key); // Thêm key vào cây con trái của root
else if (key == khóa của root)
Tăng rootcount; // Tăng số lần xuất hiện của khóa
else Insert(rootcây con phải, key); // Thêm key vào cây con phải của root
} 17/05/2023 39
Thêm khóa vào cây
 Giải thuật (đệ qui)
public void insert(Node<E> root, E key) {
if (root == null) root = new Node<E>(key);
else if (key < root.getKey()) insert(root.getLeft(), key);
else if (key == root.getKey()) root.increaseCount();
else insert(root.getRight(), key);

17/05/2023 40
Thêm khóa vào cây
Giải thuật (khử đệ qui/vòng lặp)
Insert(<nút> root, <khóa> key) {
tạo nút q có khóa là key
if (cây root rỗng) root là nút q;
else {
Tạo nút p mới và gán là root
while (p != null) { // p còn là nút của cây
… // Xem tiếp trang sau
}
// Thêm nút q vào cây
if (key < khóa của parent) q = parentnút con trái
else q = parentnút con phải
}
} 17/05/2023 41
Thêm khóa vào cây
 Giải thuật (khử đệ qui/vòng lặp)
Xử lý trong vòng lặp
while (p != null) {
parent = p;
if (key < khóa của p)
p = pnút con trái // node đến nút con trái
else if (key > khóa của p)

p = pnút con phải // node đến nút con phải

else tăng pcount; // tăng số lần xuất hiện của khóa key

} 17/05/2023 42
Thêm khóa vào cây
Giải thuật (khử đệ qui/vòng lặp)
public void insert(E key) {
Node<E> newNode = new Node<E>(key);
if (this.root == null) this.root = newNode;
else {
Node<E> parent = null;
Node<E> node = this.root;
while (node != null) {
parent = node;
if ((int)key < (int)node.getKey()) node = node.getLeft(); // chuyển node đến nút con trái
else if ((int)key > (int)node.getKey()) node = node.getRight(); // chuyển node đến nút con phải
else node.increaseCount(); // Tăng số lần xuất hiện của khóa key vì key = node.key
}
if ((int)key < (int)parent.getKey()) newNode = parent.getLeft();
else newNode = parent.getRight();
}
} 17/05/2023 43
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Tìm khóa trên cây


(Search on BST)
Tìm khóa trên cây
Có hai cách để hiện thực
• Tìm kiếm đệ qui
• Tìm kiếm khử đệ qui

 Số lần so sánh tối đa để tìm kiếm một phần tử X trên cây là h, với
h là chiều cao của cây ⇒ Độ phức tạp giải thuật tìm kiếm là
O(log2n) (Vì h ≥ log2n)

17/05/2023 45
Tìm khóa trên cây
Giải thuật
Gọi khóa cần tìm là key
Tìm kiếm khóa trong cây bao gồm 2 bước bắt đầu từ node là nút
gốc
Bước 1: Nếu node là null thì key không tồn tại; ngược lại, nếu
khóa của node là key thì tìm thấy khóa này. Kết thúc tìm kiếm
Bước 2: Nếu key < khóa của node thì tìm key trong cây con trái
của node; ngược lại, tìm key trong cây con phải của node. Lặp lại
bước 1
17/05/2023 46
Tìm khóa trên cây
Giải thuật (đệ qui)
<Nút> find(<nút> root, khóa key){
if (cây có gốc tại root rỗng) return null;// trả về NULL
else {
if (key < khóa của root) // tìm key trong cây con trái của root
return find(root cây con trái, key);
else if (key == khóa của root) return root;
else // tìm key trong cây con phải của root
return find(root  cây con phải, key);
}
} 17/05/2023 47
Tìm khóa trên cây
Giải thuật (đệ qui)
public Node<E> find(Node<E> root, E key) {
if (root == null) return null;
else {
// Giả sử khóa của cây thuộc kiểu số nguyên
if ((int)key < (int)root.getKey())
return find(root.getLeft(), key);
else if ((int)key == (int)root.getKey()) return root;
else return find(root.getRight(), key);
}
} 17/05/2023 48
Tìm khóa trên cây
Giải thuật (khử đệ qui/vòng lặp)
<Nút> find(<nút> root, khóa key){
found = false;
while (root != null và found == false)
if (key < khóa của root)
root = root  cây con trái // Tìm key trong cây con trái của root
else if (key == khóa của root)
found = true;
else root = root  cây con phải // Tìm key trong cây con phải của root
return root;
} 17/05/2023 49
Tìm khóa trên cây

Giải thuật (khử đệ qui/vòng lặp)
public Node<E> find(E key) {
Node<E> root = this.root;
boolean found = false;
while (root != null && !found) {
// Giả sử khóa của cây thuộc kiểu số nguyên
if ((int)key < (int)root.getKey())
root = root.getLeft(); // Tìm key trong cây con trái của root
else if ((int)key == (int)root.getKey()) found = true;
else root = root.getLeft(); // Tìm key trong cây con phải của root
}
return root;
} 17/05/2023 50
Tìm khóa trên cây
root
Ví dụ: tìm x = 55
44
x > 44

18 88
x < 88

13 37 59 108
x < 59

15 23 40 55 71

17/05/2023 51
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Duyệt cây
(Traverse BST)
Duyệt cây
Giống hoàn toàn với các thao tác duyệt trên cây nhị phân thông
thường
• Duyệt tiền tự Node-Left-Right (Preorder)
• Duyệt trung tự Left-Node-Right (Inorder)
• Duyệt hậu tự Left-Right-Node (Postorder)

17/05/2023 53
Duyệt cây
 Đặc biệt, khi theo thứ tự Left-Node-Right sẽ cho kết quả là dãy khóa
phân biệt được sắp xếp theo thứ tự tăng dần
44

18 88

15 37 108

13 23 99 120

30

13 15 18 23 30 37 44 88 99 108 120
17/05/2023 54
Duyệt cây
 Còn khi duyệt theo thứ tự Right-Node-Left sẽ cho kết quả là dãy khóa
phân biệt được sắp xếp theo thứ tự giảm dần
44

18 88

15 37 108

13 23 99 120

30

120 108 99 88 44 37 30 23 18 15 13
17/05/2023 55
Duyệt cây
 Giải thuật duyệt cây T theo thứ tự NLR (Node-Left-Right)

NLR(Node T) {
if (cây T khác rỗng) {
Xử lý nút T; // Node
NLR(cây con trái của T); // Left
NLR(cây con phải của T); // Right
}
}
17/05/2023 56
Duyệt cây
 Giải thuật duyệt cây T theo thứ tự NLR (Node-Left-Right)
public void traverseNLR(Node<E> root) {
if (root != null) { // Cây khác rỗng
root.display(); // Hiển thị nút node
traverseNLR(root.getLeft());// Duyệt cây con trái
traverseNLR(root.getRight());// Duyệt cây con phải
}
}
17/05/2023 57
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Kiểm tra cây NPTK


(Check BST)
Nhận xét
Nếu một cây là cây NPTK thì khi duyệt cây theo thứ tự Left-Node-
Right sẽ cho kết quả là dãy khóa phân biệt tăng dần chặt
Nếu một cây là rỗng thì nó cũng là một cây NPTK rỗng

Nếu cây không là cây NPTK thì khóa trước ≥ khóa sau

17/05/2023 59
Kiểm tra cây NPTK
Giải thuật kiểm tra cây NPTK
// Kiểm tra xem cây p có phải là cây NPTK
// key là khóa trước của khóa p
// firstTime == false khi khóa của p không là khóa đầu tiên
boolean isBinarySearchTree(Node<E> p, E key, boolean firstTime)
isBST = true;
if (cây p khác rỗng)
isBST = isBinarySearchTree(p  cây con trái, key, firstTime);
if (isBST)
if (firstTime) firstTime = false;
else if (key ≥ pkey) isBST = false;
key = p  key;
if (isBST)
isBST = isBinarySearchTree(p  cây con phải, key, firstTime);
return
17/05/2023isBST; 60
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Hủy khóa trên cây


(Remove key on BST)
Hủy khóa trên cây
Việc hủy phần tử phải đảm bảo điều kiện ràng buộc của CNPTK

Có 3 trường hợp có thể xảy ra khi hủy một nút X


 X là nút lá

 X chỉ có một con (trái hoặc phải)

 X có đủ cả 2 con

17/05/2023 62
Hủy khóa trên cây
Trường hợp 1: Hủy nút  Ví dụ: hủy X = 40
X là nút lá root 44
 Chỉ đơn giản hủy X vì
nó không móc nối đến 18 88

phần tử nào khác


13 37 59 108

15 23 40 55 71

17/05/2023 63
Hủy khóa trên cây
Trường hợp 2: Hủy nút  Ví dụ: hủy X = 37
X có một con (trái hoặc root 44
phải)
 Trước khi hủy X, ta phải 18 88

móc nối cha của X với


nút con duy nhất của nó 13 37 59 108

 Sau đó hủy X
15 23 55 71

17/05/2023 64
Hủy khóa trên cây
Trường hợp 3: Hủy nút X  Ví dụ: hủy X = 88
có đủ cả 2 con
root 44
 Ta không thể hủy trực tiếp ?
X mà phải hủy gián tiếp
18 88
 Tìm phần tử thế mạng Y
có tối đa 1 con 13 37 59 108

 Đưa thông tin của Y lên


lưu ở X rồi hủy Y 15 23 55 71

17/05/2023 65
Hủy khóa trên cây
Làm thế nào để chọn được  Ví dụ: hủy X = 88
nút Y để khi lưu Y vào vị trí
root 44
của X thì CNPTK bảo toàn ?
Cách 1: chọn Y là phần tử
18 88
nhỏ nhất (trái nhất) trên cây
con phải của X
13 37 59 108
Cách 2: chọn Y là phần tử
lớn nhất (phải nhất) trên
15 23 55 71
cây con trái của X
17/05/2023 66
Hủy khóa trên cây
Cách 1: chọn Y là phần  Ví dụ: hủy X = 18
tử nhỏ nhất (trái nhất) root 44
trên cây con phải của X
để hủy
23
18 88

13 37 59 108

15 18
23 55 71

17/05/2023 67
Hủy khóa trên cây
Cách 1: chọn Y là phần  Ví dụ: hủy X = 18
tử nhỏ nhất (trái nhất) root 44
trên cây con phải của X
để hủy
23 88

13 37 59 108

15 55 71

17/05/2023 68
Hủy khóa trên cây
Cách 2: chọn Y là phần  Ví dụ: hủy X = 23
tử lớn nhất (phải nhất) root 44
trên cây con trái của X để
hủy
23
15 88

13 37 59 108

23
15 55 71

17/05/2023 69
Hủy khóa trên cây
Cách 2: chọn Y là phần  Ví dụ: hủy X = 23
tử lớn nhất (phải nhất) root 44
trên cây con trái của X để
hủy
15 88

13 37 59 108

55 71

17/05/2023 70
Hủy khóa trên cây
Giải thuật
Gọi khóa cần loại bỏ là key

Việc loại bỏ khóa trên cây NPTK bao gồm 2 bước bắt đầu từ node là nút
gốc

Bước 1: Nếu key < khóa của node thì tiếp tục tìm để loại bỏ khóa này
trong cây con trái của node; ngược lại, nếu key > khóa của node thì tiếp
tục tìm để loại bỏ khóa này trong cây con trái của node.

Lặp lại bước này


17/05/2023 71
Hủy khóa trên cây
Giải thuật
Bước 2: nếu key = khóa của node → loại bỏ node. Có 3 trường hợp loại
bỏ node
- Trường hợp 1: nếu node là nút lá. Ta gán null cho liên kết của nút Cha
- Trường hợp 2: nếu node chỉ có 1 cây con (trái hoặc phải). Ta gắn cây
con này cho liên kết của nút Cha
- Trường hợp 3: nếu node có 2 cây con. Ta loại bỏ nút cực phải của cây
con trái của node
17/05/2023 72
Hủy khóa trên cây
Giải thuật
Việc loại bỏ một nút của cây có thể dùng kĩ thuật đệ quy hoặc vòng lặp

Dưới đây là các giải thuật


- Loại bỏ nút cực phải của cây

- Loại bỏ một khóa trong cây

17/05/2023 73
Hủy khóa trên cây
Giải thuật loại bỏ nút cực phải của cây (đệ qui)
// Gọi q là nút cần loại bỏ, r là nút cực phải của cây
RemoveRightmostNode(Node<E> r, Node<E> q) {
if (r có nút con phải)
// Tiếp tục chuyển đến nút con phải cây con r
RemoveRightmostNode(cây con phải của r, q);
else {// r là cực phải  bắt đầu loại bỏ q thông qua r;
Chép nút cực phải vào nút q;
Di chuyển q đến r;
r đến nút con trái để gắn cây con trái vào nút cha;
}
}
17/05/2023 74
Hủy khóa trên cây
Loại bỏ nút cực phải của cây bằng đệ qui (Java)
// removeNode: là nút cần loại bỏ trên cây, rightmostNode: là nút cực phải của cây
public void removeRightmostNode(Node<E> rightmostNode, Node<E> removeNode) {
if (rightmostNode.getRight() != null)
removeRightmostNode(rightmostNode.getRight(), removeNode); // Nút còn có nút con phải
else { // rightmostNode là nút cực phải --> bắt đầu loại bỏ removeNode thông qua
rightmostNode;
// Chép nút cực phải vào nút cần xóa
removeNode.setKey(rightmostNode.getKey());
removeNode.setCount(rightmostNode.getCount());
removeNode = rightmostNode; // Di chuyển removeNode đến rightmostNode;
rightmostNode = rightmostNode.getLeft(); // rightmostNode đến nút con trái để gắn cây con
trái vào nút cha;
}
} 17/05/2023 75
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (đệ qui)
boolean RemoveInsideNode(Node<E> p, E key) {// Loại bỏ khóa key trong cây p
if (cây p khác rỗng) {
if (key < khóa của p) // Loại bỏ key trong cây con trái
return RemoveInsideNode(pcây con trái, key);
else if (key > khóa của p) // Loại bỏ key trong cây con phải
return RemoveInsideNode(pcây con phải, key);
else {// T/h: key == khóa của p
… // Xem tiếp slide sau
}
}
return false; // Chưa loại bỏ được
} 17/05/2023 76
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (Tiếp theo)
else {// T/h: key == khóa của p
q = p;
if (p là nút lá) nút cha = null;
else if (p có con trái, không có con phải)
Gắn cây con trái của p vào nút cha của p;
else if (p có con phải, không có con trái)
Gắn cây con phải của p vào nút cha của p;
else // Loại bỏ nút cực phải của cây con trái của p
RemoveRightmostNode(pcon trái, q);
Hủy bỏ nút q;
return true; // Loại bỏ thành công
} 17/05/2023 77
Hủy khóa trên cây
Loại bỏ khóa trong cây bằng đệ qui (Java)
public boolean removeInsideNode(Node<E> root, E key) {
if (root != null) {
if ((int)key < (int)root.getKey()) // Loại bỏ key trong cây con trái
return removeInsideNode(root.getLeft(), key);
else if ((int)key > (int)root.getKey()) // Loại bỏ key trong cây con phải
return removeInsideNode(root.getRight(), key);
else { // T/h: key == khóa của p
// Xem tiếp slide sau
}
}
return false; // Chưa loại bỏ được
}
17/05/2023 78
Hủy khóa trên cây

Loại bỏ khóa trong cây bằng đệ qui (Java)
else { // T/h: key == khóa của p
Node<E> removeNode = root;
// T/h: root là nút lá --> loại trực tiếp
if (root.getLeft() == null && root.getRight() == null) root = null;
// root có cây con trái, ko có cây con phải
else if (root.getLeft() != null && root.getRight() == null)
root = root.getLeft(); // Gắn cây con trái vào nút cha
// root có cây con phải, ko có cây con trái
else if (root.getLeft() == null && root.getRight() != null)
root = root.getRight(); // Gắn cây con phải vào nút cha
else removeRightmostNode(root.getLeft(), removeNode); // T/h: root có cả 2 con
removeNode = null; // Hủy bỏ nút cần xóa
return true;
} 17/05/2023 79
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (vòng lặp)
// Loại bỏ khóa key trong cây p
Remove(Node<E> root, E key) {// Loại bỏ khóa key trong cây p
error = true; // Chưa loại bỏ được
found = false;
parent = null; // parent là nút cha của p
p là nút gốc root;
while (p là nút của cây và chưa tìm thấy)
if (khóa của p == key) found = true; // Tìm thấy
else if (key < khóa của p)
17/05/2023 80
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (vòng lặp)
else if (key < khóa của p)
// Tìm key trong cây con trái của p
parent đến p;
p đến nút con trái;
else if (key > khóa của p)
// Tìm key trong cây con phải của p
parent đến p;
p đến nút con phải;
17/05/2023 81
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (vòng lặp)
if (found)
error = false;
if (p là nút lá)
if (p là root) root = null;
else if (p là nút con trái của parent)
parent không có nút con trái;
else parent không có nút con phải;
17/05/2023 82
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (vòng lặp)
else if (p có cây con trái, không có cây con phải)
if (p là root) root trỏ đến cây con trái;
else if (p là nút con trái của parent)
Gắn cây con trái vào bên trái của parent;
else gắn cây con trái vào bên phải của parent;

17/05/2023 83
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (vòng lặp)
else if (p có cây con phải, không có cây con trái)
if (p là root) root trỏ đến cây con phải;
else if (p là nút con trái của parent)
Gắn cây con phải vào bên trái của parent;
else Gắn cây con phải vào bên phải của parent;

17/05/2023 84
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (vòng lặp)
else
// p có hai cây con
// Loại bỏ nút cực phải của cây con trái của p
r là nút gốc của cây con trái của p;
while (r không là nút cực phải)
parent đến r;
r đến nút con phải;
17/05/2023 85
Hủy khóa trên cây
Giải thuật loại bỏ khóa trong cây (vòng lặp)
// r là nút cực phải
Chép nội dung của r vào p;
if (r là nút con trái của p)
Gắn cây con trái của r vào bên trái của p;
else Gắn cây con trái của r vào bên phải của p;
p đến r để loại bỏ nút cực phải;
Hủy bỏ nút p;
17/05/2023 86
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Giải phóng cây NPTK


(Destroy BST)
Giải phóng cây
Việc hủy toàn bộ CNPTK  Ví dụ: giải phóng toàn bộ cây
được thực hiện theo thứ tự: root 44
hủy cây con trái, hủy cây con
phải, cuối cùng là hủy nút gốc
15 88
Sau khi hủy bỏ cây thì root 
null 13 37 59 108

55 71

17/05/2023 88
Giải phóng cây
Giải thuật

Clear(Node<E> root)

if (cây root khác rỗng)

Clear(root cây con trái);

Clear(root cây con phải);

Hủy bỏ root;

17/05/2023 89
Giải phóng cây
Chương trình (Java)
public void clear(Node<E> root) {
if (root != null) {
clear(root.getLeft());
clear(root.getRight());
root = null;
}
} 17/05/2023 90
Độ phức tạp
Trường hợp trung bình: các thao tác tìm kiếm, thêm và xóa 1 phần tử
trên CNPTK đều có độ phức tạp O(h), với h là chiều cao của cây

Trường hợp tốt nhất: CNPTK có N nút sẽ có độ cao h = log2N ⇒ chi


phí tìm kiếm tương đương với tìm kiếm nhị phân trên mảng có
thứ tự
Trường hợp xấu nhất: cây bị suy biến thành 1 danh sách liên kết
(mỗi nút đều chỉ có 1 nút con, trừ nút lá) ⇒ mọi thao tác trên cây
đều có độ phức tạp O(n)
17/05/2023 91
Cải tiến
CNPTK có thể được cải tiến thành cây nhị phân cân bằng (AVL
Tree) ⇒ khi đó mọi thao tác trên cây đều có độ phức tạp là
O(log2N)

Tự tìm hiểu về cây nhị phân cân bằng trong các giáo trình và
tài liệu!

17/05/2023 92
TRƯỜNG ĐH NGUYỄN TẤT THÀNH Môn học
KHOA CÔNG NGHỆ THÔNG TIN Cấu Trúc Dữ Liệu & Giải Thuật

Tổng kết
Summary
Tổng kết
Cây nhị phân tìm kiếm có cấu trúc linh hoạt và mềm dẻo như cây nhị
phân khi được hiện thực bằng danh sách liên kết
Cây nhị phân tìm kiếm có khả năng phân cấp và thể hiện thứ tự của các
khóa trên cây
Cách tổ chức của Cây NPTK giúp cho việc tìm kiếm phần tử trên cây
diễn ra nhanh với độ phức tạp về thời gian chỉ O(log2n) ⇔ độ phức tạp
của giải thuật tìm kiếm nhị phân trên mảng có thứ tự
Cây NPTK sẽ mất đi độ tối ưu về mặt xử lý khi nó bị suy biến thành 1
danh sách liên kết (Cây nhị phânThS.có
17/05/2023 mức
Trần Đức Hiếu bằng 1) 94
Hỏi & Đáp

“Formal education will make you a living;


self-education will make you a fortune”
17/05/2023 ThS. Trần Đức Hiếu 95
Bài học kế tiếp
Sinh viên tự tìm hiểu
Cây nhị phân cân bằng (AVL)
Cây nhị phân cân bằng hoàn toàn

 Kết thúc chương trình

17/05/2023 ThS. Trần Đức Hiếu 96


Tài liệu tham khảo
Tài liệu môn học
• [1] Michael T. Goodrich, Roberto Tamassia, Data Structures & Algorithms in Java
(6th Edition)
• [2] Trần Hạnh Nhi, Dương Anh Đức, Cấu trúc dữ liệu & giải thuật, Khoa CNTT,
trường ĐH KHTN ĐHQG TpHCM
Tài liệu tham khảo thêm
• [3] Thomas H. Cormen et al., 2009, Introduction to Algorithms, 3rd Edition, ebook.
• [4] Hoàng M. L., 2002, Cấu trúc dữ liệu và giải thuật, ĐHSP Hà Nội.
17/05/2023 ThS. Trần Đức Hiếu 97

You might also like