Professional Documents
Culture Documents
1
CÁC KHÁI NIỆM
• Cây là một tập hữu hạn các nút (đỉnh) trong đó có một
nút đặc biệt gọi là gốc (root)
• Giữa các nút có quan hệ phân cấp gọi là “quan hệ cha
con” và được biểu diễn bởi một cung (cạnh) từ cha đến
con
2
CÁC KHÁI NIỆM
3
CÁC KHÁI NIỆM
• Qui ước cho phép tồn tại cây không có nút nào và gọi đó
là cây rỗng (null tree)
• Cây mà mỗi nút chỉ có tối đa hai con gọi là cây nhị phân
4
CÁC KHÁI NIỆM
r
x1 x2 x3
x21 x22
5
CÁC KHÁI NIỆM
• Nút gốc không có cha, các nút không có con gọi là các
nút lá (leaf node), các nút còn lại là các nút trong
(internal node)
• Số con của một nút x trong cây T gọi là bậc (degree) của
x
6
CÁC KHÁI NIỆM
• Độ dài đường đi (số cạnh) từ nút gốc r đến một nút x gọi
là độ sâu (depth) của x trong T
• Độ sâu lớn nhất của các nút trong T gọi là chiều cao
(height) của T
7
CÁC KHÁI NIỆM
r Độ sâu 0
c Độ sâu 1
a Bậc của x là 2 x
z Độ sâu 3
8
CÁC KHÁI NIỆM
• Một cây được gọi là cây m-phân nếu số con nhiều nhất
của một nút của cây là m
• Một cây được gọi là m-phân đầy đủ nếu mọi nút trong có
đúng m con
• Cây m-phân độ cao h được gọi là cân bằng nếu tất cả các
lá đều ở mức h hoặc h 1
9
CÁC KHÁI NIỆM
• Một cây nhị phân là cân bằng nếu tại mọi nút của cây, độ
cao của cây con trái và cây con phải khác nhau không quá
1
• Nếu h là chiều cao của cây nhị phân cân bằng có n nút thì
h 1.44log2 n
11
BIỂU DIỄN CÂY NHỊ PHÂN
• Biểu diễn cây nhị phân
Mỗi nút x, (ngoài thông tin dữ liệu), được biểu diễn bởi một khóa
và hai con trỏ left và right chỉ đến con trái và con phải của nó
trong cây nhị phân T
Nếu left[x] = NULL thì x không có con trái
Nếu right[x] = NULL thì x không có con phải
Nút gốc của cây T được trỏ bởi root[T]
Nếu root[T] = NULL thì cây T là rỗng
12
BIỂU DIỄN CÂY NHỊ PHÂN
• Nếu mỗi nút của cây biểu diễn một đối tượng có khóa là một số
nguyên, có thể định nghĩa CTDL cây nhị phân trong C++ như
sau
13
DUYỆT CÂY NHỊ PHÂN
14
InorderTreeWalk
void InorderTreeWalk(TREE x) //LNR
{
if(x!=NULL)
{
InorderTreeWalk(x->left);
cout<<(x->key)<<' '; //thăm (xử lý) nút x
InorderTreeWalk(x->right);
}
}
15
CÂY NHỊ PHÂN TÌM KIẾM
(BINARY SEARCH TREE-BST)
• Là mô hình dữ liệu có nhiều ứng dụng trong thực tế
• Khoá của các phần tử được lưu trữ thỏa mãn tính chất cây nhị
phân tìm kiếm (binary search tree property)
Nếu y là một nút trong cây con trái của nút x thì
key[y]< key[x]
Nếu y là một nút trong cây con phải của nút x thì
key[y]> key[x]
16
CÂY BST
17
CÁC THAO TÁC TRÊN CÂY BST
18
TreeInitialize
void TreeInitialize(TREE &T)
{
T=NULL;
}
19
CÁC THAO TÁC TÌM KIẾM
20
CÁC THAO TÁC TÌM KIẾM
21
TreeSearch
• Đầu vào là một pointer x chỉ đến gốc của cây nhị phân tìm
kiếm và khoá k của phần tử cần tìm
• Thủ tục trả về pointer chỉ đến nút có khoá k hoặc NULL
• Dựa vào tính chất của cây nhị phân tìm kiếm để xác định nút
nào phải tìm kế tiếp trong các con trái và phải của x
Nếu k < key[x], tìm tiếp trong cây con trái
Ngược lại, tìm tiếp trong cây con trái
22
TreeSearch
TREE TreeSearch(TREE x,int k)
{
if(x==NULL||k==x->key) return x;
if(k<x->key) return TreeSearch(x->left,k);
else return TreeSearch(x->right,k);
}
23
TreeMinimum
• Đầu vào là một pointer x chỉ đến gốc của cây nhị phân tìm
kiếm
• Thủ tục trả về pointer chỉ đến nút có khoá nhỏ nhất
• Dựa vào tính chất của cây nhị phân tìm kiếm, phần tử có khoá
nhỏ nhất được tìm kiếm theo các pointer chỉ đến con trái bắt
đầu từ gốc cho đến khi pointer này là NULL
24
TreeMinimum
TREE TreeMinimum(TREE x)
{
if(x!=NULL) while(x->left!=NULL) x=x->left;
return x;
}
25
TreeMaximum
• Đầu vào là một pointer x chỉ đến gốc của cây nhị phân
tìm kiếm
• Thủ tục trả về pointer chỉ đến nút có khoá lớn nhất
• Phần tử có khoá nhỏ nhất được tìm kiếm theo các pointer
chỉ đến con phải bắt đầu từ gốc cho đến khi pointer này
là NULL
26
TreeMaximum
TREE TreeMaximum(TREE x)
{
if(x!=NULL) while(x->right!=NULL) x=x->right;
return x;
}
27
ĐỘ PHỨC TẠP
• Các thao tác tìm kiếm trên cây nhị phân tìm kiếm có độ
phức tạp là O(h), trong đó h là chiều cao của cây
28
CHÈN VÀ XOÁ
29
TreeInsert
30
TreeInsert
Chèn một phần tử có khoá 13 vào cây, các nút được
làm sáng chỉ đường đi từ gốc đến vị trí cần chèn
12
18
5 15 19
2 9 13 17
31
TreeInsert
void TreeInsert(TREE &T, int k)
{
if(T==NULL)
{
T=new(CELL); T->key=k; T->left=NULL; T->right=NULL;
}
else if(k<T->key) TreeInsert(T->left, k);
else if(k>T->key) TreeInsert(T->right, k);
}
32
TreeDelete
• TreeDelete(T, k) tìm và xoá nút z có khóa k, xét ba trường hợp
Nếu z không có con, sửa con trỏ của cha z đến z thành
NULL
Nếu z chỉ có một con, loại bỏ z bằng một liên kết mới giữa
cha và con của nó
Nếu z có hai con, loại phần tử có khóa nhỏ nhất y trong cây
con phải của z và thay thế khóa (dữ liệu) của z bởi khóa (dữ
liệu) của y
33
TreeDelete
12 12
5 18 5 18
2 9 15 20 2 9 15 20
z 13 19 19
34
TreeDelete
12 12
5 18 5 18
z
2 9 15 20 2 9 13 20
13 19 19
35
TreeDelete
12 12 19
5 z 18 5 z 18
2 9 15 20 2 9 15 20
19 13 y 19
13
36
TreeDelete
12 12
5 z 18 5 z 19
2 9 15 20 2 9 15 20
13 19 13
37
TreeDelete
void TreeDelete(TREE &T, int k)
{
if(T!=NULL)
if(k<T->key) TreeDelete(T->left,k);
else if(k>T->key) TreeDelete(T->right,k);
else if(T->right==NULL) T=T->left;
else if(T->left==NULL) T=T->right;
else T->key=DeleteMin(T->right);
}
38
DeleteMin
int DeleteMin(TREE &T)
{
int min;
if(T->left==NULL)
{
min=T->key;
T=T->right;
return min;
}
else return DeleteMin(T->left);
}
39
ĐỘ PHỨC TẠP
• Định Lý 1: Các thao tác chèn (TreeInsert) và xóa
(TreeDelete) thực hiện trong thời gian O(h) trên một cây
nhị phân tìm kiếm độ cao h
40
ĐỘ PHỨC TẠP
• Độ cao của cây nhị phân tìm kiếm biến đổi thông qua các
thao tác chèn và xoá các nút trên cây
• Thời gian thao tác là O(h), vì vậy khi cây suy biến và có
chiều cao là n-1 (n là số nút trên cây) thì các thao tác này
sẽ không còn hiệu quả
• Xác suất để xẩy ra sự suy biến khi chèn, xoá một cách
ngẩu nhiên là rất nhỏ
41
ĐỘ PHỨC TẠP
• Định Lý 2: Độ cao trung bình của một cây nhị phân tìm
kiếm được xây dựng ngẩu nhiên trên n khoá phân biệt là
O(log2 n)
• Định Lý 3: Độ phức tạp trung bình của các thao tác tìm
kiếm, chèn và xóa trên một cây nhị phân tìm kiếm n nút
có khóa phân biệt là O(log2 n)
42
CÂY NHỊ PHÂN TÌM KIẾM CÂN BẰNG
• Định nghĩa
• Các trường hợp mất cân bằng
• Các thao tác cân bằng cho cây mất cân bằng
• Chèn một phần tử vào cây cân bằng
• Xóa một phần tử khỏi cây cân bằng
43
ĐỊNH NGHĨA
• Một cây nhị phân được gọi là cân bằng hoàn toàn nếu tại
mỗi nút, cây con trái và cây con phải của nó có số nút
chênh lệch nhau không quá 1
44
ĐỊNH NGHĨA
• Một cây nhị phân được gọi là cân bằng nếu tại mỗi nút,
cây con trái và cây con phải của nó có độ cao chênh lệch
nhau không quá 1
• Cây cân bằng còn được gọi là cây AVL (do các nhà khoa
học Adelson, Velskii và Landis đưa ra năm 1962)
• Chiều cao cây cân bằng n nút luôn luôn là O(log2n)
45
ĐỊNH NGHĨA
typedef struct AVLNode *AVLTree;
struct AVLNode {
int balFactor;
int key;
AVLTree pLeft, pRight;
};
AVLTree T;
46
ĐỊNH NGHĨA
• Các hằng số biểu diễn quan hệ về độ cao các cây con
#define LH -1 //Cây con trái cao hơn
#define EH 0 //Hai cây con có chiều cao bằng nhau
#define RH 1 //Cây con phải cao hơn
47
CÁC TRƯỜNG HỢP MẤT CÂN BẰNG
• Khi cây T mất cân bằng, chênh lệch độ cao các cây con
của T là 2
• Cây T lệch bên trái (3 trường hợp)
• Cây T lệch bên phải (3 trường hợp)
48
CÂY LỆCH BÊN TRÁI
Trường hợp 1 Trường hợp 2
T1 T1
h-1 h-1
h h-1 h h
49
CÂY LỆCH BÊN TRÁI
Trường hợp 3
T1
h-1
h-1 h
50
CÂY LỆCH BÊN PHẢI
Trường hợp 1 Trường hợp 2
h-1 T1
h-1 T1
h-1 h h h
51
CÂY LỆCH BÊN PHẢI
Trường hợp 3
h-1 T1
h h-1
T1 T
h-1 h L1
R
53
CÂN BẰNG CÂY LỆCH BÊN TRÁI
Trường hợp 2
T1 T
h-1 h L1
R
h L1 R1 h h R1 R h-1
54
CÂN BẰNG CÂY LỆCH BÊN TRÁI
Trường hợp 3 Xác định T2 là con T1
T1
T1 h-1
h-1 R
R
T2
h-1 L1 R1
h-1 L1 R1
h
h
L2 R2
T1 lệch phải
55
CÂN BẰNG CÂY LỆCH BÊN TRÁI
Trường hợp 3
T1
h-1 T1 T
R
T2
h-1 L1 R1
h-1 L1 L2 R2 R h-1
h
L2 R2
57
QUAY ĐƠN LEFT-LEFT
Trường hợp 1
T1 T
h-1 h L1
R
58
QUAY ĐƠN LEFT-LEFT
T1
Ví dụ T
50 40
T1 40 T
30 50
60
30 45 45 60
20
20
T1 lệch trái, sử dụng phép quay Left-Left (trường hợp 2)
59
CÂN BẰNG CÂY LỆCH BÊN TRÁI
Trường hợp 2
T1 T
h-1 h L1
R
h L1 R1 h h R1 R h-1
60
QUAY ĐƠN LEFT-LEFT
T1
Ví dụ T
50 40
T1 40 T
30 50
60
30 45 45 60
20
20 48 48
62
QUAY ĐƠN RIGHT-RIGHT
void rotateRR(AVLTree &T)
{ AVLTree T1=T->pRight;
T->pRight=T1->pLeft;
T1->pLeft=T;
switch(T1->balFactor) {
case RH: T->balFactor=EH; T1->balFactor=EH; break;
case EH: T->balFactor=RH; T1->balFactor=LH; break;
}
T=T1;
}
63
CÂN BẰNG CÂY LỆCH BÊN TRÁI
Trường hợp 3
T1
h-1 T1 T
R
T2
h-1 L1 R1
h-1 L1 L2 R2 R h-1
h
L2 R2
T1 30
60 T1 T
30 50
T2
20 40
20 35 45 60
35 45
68
HÀM CÂN BẰNG KHI CÂY LỆCH PHẢI
void balanceRight(AVLTree &T)
{ AVLTree T1=T->pRight;
switch(T1->balFactor) {
case LH: rotateRL(T);
case EH: rotateRR(T);
case RH: rotateRR(T);
}
}
69
CHÈN MỘT PHẦN TỬ VÀO CÂY AVL
• Tìm và chèn tương tự như trên cây nhị phân tìm kiếm
• Sau khi chèn phải cân bằng lại
• Thao tác insertNode trả về -1, 0, 1 khi không đủ bộ nhớ,
gặp nút đã có hoặc chèn thành công (chiều cao không
tăng)
• Thao tác insertNode trả về 2 nếu chèn thành công và
chiều cao tăng
70
CHÈN MỘT PHẦN TỬ VÀO CÂY AVL
int insertNode(AVLTree &T, int x)
{ int res;
if(T) { if(T->key==x) return 0;
if(T->key>x){
res= insertNode(T->pLeft, x);
if(res<2) return res;
switch(T->balFactor) {
case RH: T->balFactor=EH; return 1;
case EH: T->balFactor=LH; return 2;
case LH: balanceLeft(T); return 1;
}
} else
71
CHÈN MỘT PHẦN TỬ VÀO CÂY AVL
int insertNode(AVLTree &T, int x)
{ int res;
if(T) { if(T->key==x) return 0;
if(T->key>x){ //-------; các lệnh đã có
} else { res= insertNode(T->pRight, x);
if(res<2) return res;
switch(T->balFactor) {
case LH: T->balFactor=EH; return 1;
case EH: T->balFactor=RH; return 2;
case RH: balanceRight(T); return 1;
}
}
} //kết thúc T khác rỗng
72
CHÈN MỘT PHẦN TỬ VÀO CÂY AVL
int insertNode(AVLTree &T, int x)
{ int res;
if(T) {
//….; các lệnh đã có
} //kết thúc T khác rỗng
T=new(AVLNode);
if(T==NULL) return -1; //thiếu bộ nhớ
T->key=x; T->balFactor=EH;
T->Pleft=T->pRight=NULL;
return 2; //chiều cao tăng
}
73
XÓA MỘT PHẦN TỬ KHỎI CÂY AVL
• Tìm và xóa tương tự như trên cây nhị phân tìm kiếm
• Sau khi xóa phải cân bằng lại
• Thao tác delNode trả về 1, 0 khi xóa thành công hoặc
không có x trong cây (chiều cao không giảm)
• Thao tác delNode trả về 2 nếu xóa thành công và chiều
cao giảm
• Tham khảo chương trình (hàm delNode) trong sách
CTDL> của Trần Hạnh Nhi và Dương Anh Đức
74
ĐỘ PHỨC TẠP
• Thao tác cân bằng tại một nút có độ phức tạp là O(1)
• Thao tác thêm và xóa có độ phức tạp là O(h)
• Nếu cây có n nút, độ phức tạp thêm và xóa là O(log2 n)
75
BIỂU DIỄN CÂY ĐA PHÂN
• Cơ chế biểu diễn cây nhị phân có thể mở rộng cho cây đa
phân
• Nếu mỗi nút có tối đa k con thì có thể dùng k+1 biến là p
(chỉ đến cha) và child1, child2, ..., childk (chỉ đến k con)
• Phương pháp này không hiệu quả (tốn nhiều bộ nhớ) và
không sử dụng được nếu số con tối đa của một nút quá
lớn
76
BIỂU DIỄN CÂY ĐA PHÂN
• Sử dụng 3 biến p, left-child, right-sibling để lưu trữ các pointer
chỉ đến cha, con trái trái nhất và anh, em bên phải của mỗi nút
trong T
• root[T] là pointer chỉ đến gốc của T
• left-child[x] chỉ đến con trái nhất của x
• right-sibling[x] chỉ đến anh em trực tiếp bên phải của x
• Nếu x không có con left-child[x] = NIL
• Nếu x là con phải nhất thì right-sibling[x] = NIL
77
BIỂU DIỄN CÂY ĐA PHÂN
78
CÁC BIỂU DIỄN KHÁC CỦA CÂY
• Có thể biểu diễn cây có gốc như một đồ thị có hướng
• Có thể biểu diễn cây có gốc mà không cần pointer chỉ đến
cha của nó
• Ngoài ra có thể dùng một mảng một chiều để biểu diễn
cây có gốc
79
ĐỌC VÀ TÌM HIỂU Ở NHÀ
• Đọc chương 12 sách Introduction to Algorithms của
Thomas H. Cormen, Charles E. Leiserson, Ronald D.
Rivest.
80