❖ĐỊNH NGHĨACây nhị phân tìm kiếm Binary Search Tree - BST: là cây nhị phân thỏa tính chất: tại mỗi nút k, khóa của k lớn hơn khóa của tất cả các nút nằm trên cây con bên trái nếu có của
Trang 1ĐẠI HỌC QUỐC GIA TPHCM
TRƯỜNG ĐẠI HỌC
CÔNG NGHỆ THÔNG TIN
CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT
CHƯƠNG IV
CẤU TRÚC CÂY
Nguyễn Trọng Chỉnh
Trang 2CẤU TRÚC CÂY
❖KHÁI NIỆM
❖CÂY NHỊ PHÂN
❖ CÂY NHỊ PHÂN TÌM KIẾM
❖CÂY NHỊ PHÂN CÂN BẰNG
Trang 3❖ĐỊNH NGHĨA
Cây nhị phân tìm kiếm (Binary Search Tree - BST):
là cây nhị phân thỏa tính chất: tại mỗi nút k, khóa của k lớn hơn khóa của tất cả các nút nằm trên cây con bên trái (nếu có) của k và nhỏ hơn khóa của tất
cả các nút nằm trên cây con bên phải (nếu có) của k.
Mỗi nút trên cây nhị phân tìm kiếm đều là gốc của một cây nhị phân tìm kiếm.
CÂY NHỊ PHÂN TÌM KIẾM
Trang 5❖ỨNG DỤNG
Cây nhị phân tìm kiếm được sử dụng để tăng hiệu quả tìm kiếm trên cấu trúc liên kết động nhờ vào thứ
tự của các nút trên cây.
Chí phí tìm kiếm trên cây nhị phân tìm kiếm trong
trường hợp xấu nhất là h, với h là chiều cao của
cây.
Cho cây T có n phần tử, chiều cao của cây T là:
- Trong trường hợp tốt nhất h = log2(n)
- Trong trường hợp xấu nhất h = n
CÂY NHỊ PHÂN TÌM KIẾM
Trang 6❖CÁC THAO TÁC
- Thêm một nút có khóa x
- Tìm nút có giá trị khóa là x
- Xóa nút có khóa x
- Hủy toàn bộ cây
CÂY NHỊ PHÂN TÌM KIẾM
Trang 7❖CÁC THAO TÁC
- Thêm một nút
Thuật toán:
Đầu vào: cây với gốc root, giá trị khóa cần thêm x
Đầu ra: cây với gốc root đã được nút có khóa x
B1: Nếu root = NULL thì pCreateNode(x), rootp,qua B4B2: Nếu root->key = x thì qua B4
B3: Nếu root->key < x thì thực hiện thêm nút vào cây có gốc là root->pRight Ngược lại thực hiện thêm nút vào cây có gốc là root->pLeft
B4: Kết thúc
CÂY NHỊ PHÂN TÌM KIẾM
Trang 11struct Node {
int key;
Node *pLeft, *pRight;
};
typedef Node *TREE;
void CreateTree(TREE &root) {
root = NULL;
}
CÂY NHỊ PHÂN TÌM KIẾM
Trang 13int AddNode(TREE &root, int x) {
if (root->key > x) return AddNode(root->pLeft, x);
else return AddNode(root->pRight, x);
}
CÂY NHỊ PHÂN TÌM KIẾM
Trang 15CÂY NHỊ PHÂN TÌM KIẾM
Trang 16CÂY NHỊ PHÂN TÌM KIẾM
Trang 17CÂY NHỊ PHÂN TÌM KIẾM
Trang 18CÂY NHỊ PHÂN TÌM KIẾM
Trang 19❖CÁC THAO TÁC
- Tìm nút có giá trị khóa là x
Thuật toán:
Đầu vào: cây với gốc root, giá trị khóa cần tìm x
Đầu ra: nút có khóa x
B1: Nếu root = NULL thì trả về NULL, qua B5
B2: Nếu root->key = x thì trả về root, qua B5
B3: Nếu root->key < x thì thực hiện tìm nút p có khóa x trên cây có gốc là root->pRight Ngược lại thực hiện tìm nút p
có khóa x trên cây có gốc là root->pLeft
B4: Trả về p
B5: Kết thúc
CÂY NHỊ PHÂN TÌM KIẾM
Trang 20❖CÁC THAO TÁC
- Tìm nút có giá trị khóa là x
Node * Search(TREE root, TenDulieu x) {
Node *p;
if (root == NULL) return NULL;
if (Compare(root->key, x) == 0) return root;
Trang 21❖CÁC THAO TÁC
- Xóa nút có khóa x
Có 3 trường hợp cần xử lý:
- TH1: Nút cần xóa không có cây con
- TH2: Nút cần xóa có 1 cây con
- TH3: Nút cần xóa có 2 cây con
CÂY NHỊ PHÂN TÌM KIẾM
Trang 23❖CÁC THAO TÁC
- Xóa nút có khóa x: TH2
- Gán lại địa chỉ trỏ đến p của
nút cha là nút con duy nhất
Trang 24❖CÁC THAO TÁC
- Xóa nút có khóa x: TH3
- Tìm phần tử thay thế q
(standby) cho p q là phần
tử trái nhất của cây con bên
phải hoặc là phần tử phải
nhất của cây con bên trái
Trang 25❖CÁC THAO TÁC
- Xóa nút có khóa x
Đầu vào: cây với nút gốc root, giá trị khóa x cần xóa
Đầu ra: cây với nút gốc root đã xóa phần tử có khóa x
B1: Nếu root = NULL thì qua B8
B2: Nếu root->key < x thì thực hiện xóa nút có khóa x cho cây root->pRight, qua B8
B3: Nếu root->key > x thì thực hiện xóa nút có khóa x cho cây root->pLeft, qua B8
B4: q = root
B5: Nếu root->pLeft = NULL thì root = root->pRight, qua B7
CÂY NHỊ PHÂN TÌM KIẾM
Trang 26B6: Nếu root->pRight = NULL thì root = root->pLeft,
Ngược lại tìm phần tử thay thế q cho root trên cây con root->pRight
B7: Giải phóng q
B8: Kết thúc
CÂY NHỊ PHÂN TÌM KIẾM
Trang 27❖CÁC THAO TÁC
- Xóa nút có khóa x
void SearchStandFor(TREE &p, TREE &q);
void DeleteNode(TREE &root, TenDulieu x) {
Trang 28q = root;
if (root->pLeft == NULL) root = root->pRight;
else
if (root->pRight == NULL) root = root->pLeft;
else SearchStandFor(q, root->pRight);
delete q;
}
CÂY NHỊ PHÂN TÌM KIẾM
Trang 29void SearchStandFor(TREE &q, TREE &p) {
Trang 31CÂY NHỊ PHÂN TÌM KIẾM
7 4
Trang 32❖CÁC THAO TÁC
- Hủy toàn bộ cây
Đầu vào: cây có nút gốc root
Đầu ra: cây đã được hủy có nút gốc root
B1: nếu root == NULL, qua B5
B2: Hủy toàn bộ cây có gốc là root->pLeft
B3: Hủy toàn bộ cây có gốc là root->pRight
B4: Giải phóng vùng nhớ của root, root = NULL
B5: Kết thúc
CÂY NHỊ PHÂN TÌM KIẾM
Trang 33❖CÁC THAO TÁC
- Hủy toàn bộ cây
void DeleteTree(TREE &root) {
if (root == NULL) return;
Trang 34CẤU TRÚC CÂY
❖KHÁI NIỆM
❖CÂY NHỊ PHÂN
❖CÂY NHỊ PHÂN TÌM KIẾM
Trang 35❖ĐỊNH NGHĨA
Cây nhị phân cân bằng hoàn toàn là cây mà tại mỗi nút của nó số nút của cây con trái và số nút của cây con phải chênh lệch không quá 1.
Tính chất:
- Thời gian tìm kiếm xấu nhất:
O(logn)
- Khó duy trì tình trạng cân bằng hoàn toàn.
CÂY NHỊ PHÂN CÂN BẰNG
Trang 36❖ĐỊNH NGHĨA
Cây nhị phân cân bằng (cây AVL) là cây mà mỗi nút của nó, độ cao của cây con trái và độ cao của cây con phải chênh lệch không quá 1.
Tính chất:
- Cao không quá 45% chiều cao cây cân bằng hoàn toàn
- Chi phí cân bằng cây nhỏ hơn
CÂY NHỊ PHÂN CÂN BẰNG
Trang 37❖ĐỊNH NGHĨA
Chỉ số cân bằng (CSCB) tại một nút p là hiệu số
chiều cao cây con phải của p với chiều cao cây con trái của p Nếu:
CÂY NHỊ PHÂN CÂN BẰNG
Trang 38❖ỨNG DỤNG CỦA CÂY CÂN BẰNG
Cây cân bằng nhằm đảm bảo độ cao của cây nhị
phân gần với giá trị log2(n) với n là số nút của cây
Vì vậy, các cây nhị phân tìm kiếm nếu là cây nhị
phân cân bằng thì chi phí cho việc tìm kiếm sẽ được giảm.
CÂY NHỊ PHÂN CÂN BẰNG
Trang 39❖CÁC TRƯỜNG HỢP MẤT CÂN BẰNG
Các trường hợp mất cân bằng xảy ra trong cây AVL khi thêm nút hoặc xóa nút, không xét trường hợp mất cân bằng trong cây nhị phân tìm kiếm tổng quát
Có 4 trường hợp mất cân bằng:
CÂY NHỊ PHÂN CÂN BẰNG
Trang 40❖CÁC TRƯỜNG HỢP MẤT CÂN BẰNG
- Trường hợp 1 (LL): cây tại p lệch trái, cây con trái
không lệch phải
Cần xoay phải tại nút mất cân bằng T:
- Chuyển nút con phải của T1 thành con trái của T
CÂY NHỊ PHÂN CÂN BẰNG
T
T1
Trang 41❖CÁC TRƯỜNG HỢP MẤT CÂN BẰNG
- Trường hợp 2 RR: cây tại p lệch phải, cây con phải
không lệch trái
Cần xoay phải tại nút mất cân bằng T:
- Chuyển nút con trái của T1 thành con trái của T
- Chuyển T thành nút con trái của T1 và đặt T1 là gốc
CÂY NHỊ PHÂN CÂN BẰNG
T
T1
Trang 42❖CÁC TRƯỜNG HỢP MẤT CÂN BẰNG
- Trường hợp 3 LR: cây tại p lệch trái, cây con trái
lệch phải
- Thực hiện phép xoay trái tại nút T1:
- Sau đó thực hiện phép xoay phải tại nút T
CÂY NHỊ PHÂN CÂN BẰNG
5
T2
T T1
T1
Trang 43❖CÁC TRƯỜNG HỢP MẤT CÂN BẰNG
- Trường hợp 4 RL: cây tại p lệch phải, cây con trái
lệch trái
- Thực hiện phép xoay phải tại nút T1:
- Sau đó thực hiện phép xoay trái tại nút T
CÂY NHỊ PHÂN CÂN BẰNG
20
Trang 44❖CÁC THAO TÁC TRÊN CÂY AVL
Trang 45❖CÁC THAO TÁC TRÊN CÂY AVL
typedef AVLNode *AVLTREE;
CÂY NHỊ PHÂN CÂN BẰNG
Trang 46❖CÁC THAO TÁC TRÊN CÂY AVL
Trang 47❖CÁC THAO TÁC TRÊN CÂY AVL
Trang 48❖CÁC THAO TÁC TRÊN CÂY AVL
Trang 49❖CÁC THAO TÁC TRÊN CÂY AVL
- Phép xoay trong các trường hợp
void LL(AVLTREE &T) {
Trang 50❖CÁC THAO TÁC TRÊN CÂY AVL
- Phép xoay trong các trường hợp
void RR(AVLTREE &T) {
switch(T->pRight-> balFactor) {
case RH: T-> balFactor = EH;
T->pRight-> balFactor = EH; break;
case EH: T-> balFactor = RH;
T->pRight-> balFactor = LH; break;
Trang 51❖CÁC THAO TÁC TRÊN CÂY AVL
- Phép xoay trong các trường hợp
void LR(AVLTREE &T) {
Trang 52❖CÁC THAO TÁC TRÊN CÂY AVL
- Phép xoay trong các trường hợp
void RL(AVLTREE &T) {
switch(T->pRight->pLeft-> balFactor)
{ case RH: T-> balFactor = LH;
T->pRight-> balFactor = EH; break;
case EH: T-> balFactor = EH;
T->pRight-> balFactor = EH; break;
case LH: T-> balFactor = EH;
T->pRight-> balFactor = RH; break;
Trang 53❖CÁC THAO TÁC TRÊN CÂY AVL
- Cân bằng cây - Cân bằng lệch trái: trả về 1 nếu chiều cao
cây không đổi, trả về 2 nếu chiều cao cây có thay đổi
int BalanceLeft(AVLTREE &T) {
Trang 54❖CÁC THAO TÁC TRÊN CÂY AVL
- Cân bằng cây - Cân bằng lệch phải: trả về 1 nếu chiều
cao cây không đổi, trả về 2 nếu chiều cao cây có thay đổi
int BalanceRight(AVLTREE &T) {
Trang 55❖CÁC THAO TÁC TRÊN CÂY AVL
- Thêm một nút có khóa x: Khi thêm một nút, cần đảm bảo
tính chất cân bằng của cây bằng cách:
B1) Thêm một nút có khóa x vào cây tương tự như cây nhị phân tìm kiếm
B2) Xét các nút từ vị trí nút cha của nút thêm vào về gốc để xác định nút p mất cân bằng
B3) Cân bằng tại nút p
CÂY NHỊ PHÂN CÂN BẰNG
Trang 56❖CÁC THAO TÁC TRÊN CÂY AVL
- Thêm một nút có khóa x: trả về -1 nếu không đủ bộ nhớ, 0
nếu đã tồn tại nút x, 1 nếu thêm thành công và cây không thay đổi chiều cao, 2 nếu thêm thành công và cây thay đổi chiều cao
int Compare(TenDulieu x, TenDulieu x);
int AddAVLNode(AVLTREE &T, TenDulieu x) {
int ret;
if (T == NULL) {
T = CreateAVLNode(x);
if (T== NULL) return -1; else return 2;
CÂY NHỊ PHÂN CÂN BẰNG
Trang 57case RH: T->balFactor = EH; return 1;
case EH: T->balFactor = LH; return 2;
case LH: BalanceLeft(T); return 1;
}
}
CÂY NHỊ PHÂN CÂN BẰNG
Trang 58else {
ret = AddAVLNode(T->pRight, x);
if (ret < 2) return ret;
switch(T->balFactor) {
case LH: T->balFactor = EH; return 1;
case EH: T->balFactor = RH; return 2;
case RH: BalanceRight(T); return 1;
Trang 59❖CÁC THAO TÁC TRÊN CÂY AVL
- Hủy một nút có khóa x: Khi hủy một nút, cần đảm bảo tính
chất cân bằng của cây bằng cách:
B1) Hủy nút có khóa x trên cây tương tự như cây nhị phân tìm kiếm
B2) Xét các nút từ vị trí nút cha của nút bị hủy về gốc để xác định nút p mất cân bằng
B3) Cân bằng tại nút p
B4) Tiếp tục tìm nút mất cân bằng từ nút p vế nút gốc và cân bằng các nút này
CÂY NHỊ PHÂN CÂN BẰNG
Trang 60❖CÁC THAO TÁC TRÊN CÂY AVL
- Hủy một nút có khóa x: 0 nếu không tồn tại nút x, 1 nếu
hủy thành công và cây không thay đổi chiều cao, 2 nếu hủy thành công và cây thay đổi chiều cao
int AVLSearchStandFor(AVLTREE &p, AVLTREE &q);
int DeleteAVLNode(AVLTREE &T, TenDulieu x) {
Trang 61switch (T->balFactor) {
case LH: T->balFactor = EH; return 2;
case EH: T->balFactor = RH; return 1;
case RH: return BalanceRight(T);
}
}
CÂY NHỊ PHÂN CÂN BẰNG
Trang 62if (Compare(T->key, x) < 0) {
ret = DeleteAVLNode(T->pRight, x);
if (ret < 2) return ret;
switch (T->balFactor) {
case RH: T->balFactor = EH; return 2;
case EH: T->balFactor = LH; return 1;
case LH: return BalanceLeft(T);
}
}
CÂY NHỊ PHÂN CÂN BẰNG
Trang 63ret = AVLSearchStandFor(p, T->pRight);
if (ret < 2) return ret;
switch (T->balFactor) {
case RH: T->balFactor = EH; return 2;
case EH: T->balFactor = LH; return 1;
case LH: return BalanceLeft(T);
}
CÂY NHỊ PHÂN CÂN BẰNG
Trang 65int AVLSearchStandFor(AVLTREE &p, AVLTREE &q) {
int ret;
if (q->pLeft) {
ret = AVLSearchStandFor(p, q->pLeft);
if (ret < 2) return ret;
switch (q->balFactor) {
case LH: q->balFactor = EH; return 2;
case EH: q->balFactor = RH; return 1;
case RH: return BalanceRight(q);
}
}
CÂY NHỊ PHÂN CÂN BẰNG
Trang 67CÂY NHỊ PHÂN CÂN BẰNG
50
70 20
Trang 68CÂY NHỊ PHÂN CÂN BẰNG
50
70 20
Trang 69CÂY NHỊ PHÂN CÂN BẰNG
50
70 8
36
Xóa nút x=20
37 35
Trang 70CÂY NHỊ PHÂN CÂN BẰNG