Kỹ thuật lập trì nh
105
CHươNG 6 các thuật toán trên cấu trúc câY
(Tree)
Câ y là một cấ u trúc dữ liệ u rấ t thông dụng và quan trọng trong nhiề u phạ m
vi khá c nhau của kỹ thuậ t má y tí nh.
Ví dụ
: Tổ chức cá c quan hệ họ hà ng trong một gia phả , mục lục của một
cuốn sá ch, xâ y dựng cấ u trúc về cú phá p trong cá c trì nh biê n dịch.
Trong chương trì nh nà y, chúng ta khả o sá t cá c khá i niệ m cơ bả n về câ y, cá c
phép toá n trê n câ y nhị phâ n, cũng như cá c phép toá n trê n câ y nhị phâ n câ n bằ ng
( AVL tree) và ứng dụng của hai loạ i câ y nhị phâ n tì m kiế m (BST), câ y nhị phâ n
câ n bằ ng ( AVL tree).
I. Phân loại cây
:
I.1. Một số khái niệ m cơ bản
:
1. Cây
: Câ y là tậ p hợp cá c phầ n tử gọi là nút, một nút (tương tự như một
phầ n tử của d y) có thể có kiể u bấ t kỳ. Cá c nút đ ược biể u diễ n bởi 1 ký tự chữ,
một chuỗi, một số ghi trong một vòng tròn.
Một số định nghĩ a theo đệ quy
( Một nút đơn cũng chí nh là một câ y.
( Cá c nút đ ược gọi là ở cùng một câ y khi có đ ường đi giữa cá c nút nà y.
( Một câ y sẽ bao gồm một nút gốc (Root) và m câ y con, trong mỗi câ y con
lạ i có một nút gốc và m1 câ y con nhỏ hơn v.v.
( Một câ y không có một nút nà o cả gọi là câ y rỗng.
Ví dụ 1
:
A
B C
G H E
J
D
F
KI
1
2
3
4
Nuựt goỏc
Hì nh 5.1. Câ y với nút gốc là A
- A là nút gốc với 3 câ y con lầ n
lượt có 3 nút gốc riê ng là ứ B, C, D
- Nút cha
(ancestor)
Nút con
(descendent)
A là nút cha của B, C, D
G, H là nút con của C
G, H không quan hệ cha con
với A
Kỹ thuật lập trì nh
106
Ví dụ 2 : Với đề cương một môn học T, ta có thể biể u diễ n dạ ng câ y như
sau :
T
CHệễNG I
CHệễNG II
CHệễNG III
I.1 I.2 II.1 II.3II.2
II.1.1 II.1.2
Hì nh 5.2
CHươNG I
I.1
I.2
CHươNG II
II.1
II.1.1
II.1.2
II.2
II.3
CHươNG III
2. Nút cha
(Ancestor)
: Nút đứng trê n của một nút đ ược gọi là nút cha
C là nút cha của G, H
Nút con
(descendent)
: Nút đứng sau một nút khá c đ ược gọi là nút con của
nút đó.
Nút I, J, K là nút con của nút E
3. Bậc
(degree)
:
- Bậ c của nút là số câ y con của nút đó.
C có bậ c là 2, E có bậ c là 3 (Hì nh 5.1)
- Bậ c của câ y là bậ c lớn nhấ t của cá c nút trong câ y.
Câ y trong hì nh 5.1 có bậ c là 3.
Câ y bậ c n đ ược gọi là câ y n phâ n như câ y nhị phâ n, câ y tam phâ n.
4. Nút lá và nút trung gian
:
- Nút lá là nút có bậ c bằ ng 0 (tức là không có câ y con nà o) :
- Nút trung gian: là một nút có bậ c khá c 0 và không phả i là nút gốc.
Ví dụ
: Trong hì nh 5.1, B, G, H, I, J, K, F là nút lá
C, D, E là nút trung gian.
5. Mức của nút
(level)
: Nút gốc có mức là 1
Mức của nút con = mức của nút cha + 1
Kỹ thuật lập trì nh
107
Ví dụ: trong hì nh 5.1,
A có mức là 1
B, C, D có mức là 2
G, H, E, F có mức là 3
I, J, K có mức là 4
6. Chiề u cao của cây
(height)
: là mức lớn nhấ t của cá c nút lá trong câ y.
Ví dụ
: Câ y trong hì nh 5.1 có chiề u cao là 4
7. Thứ tự của các nút
(order of nodes)
: Nế u câ y đ ược gọi là có thứ tự thì
phả i đả m bả o vị trí của cá c nút con từ trái qua phả i, tức là nế u thay đổi vị trí của
một nút con bấ t kỳ thì ta đ có một câ y mới.
Ví dụ
:
A
B C
A
C B
caõy khaực
Hì nh 5.3: Sau khi đổi vị trí của 2 nút B, C ta đ có câ y mới.
8. Chiề u dài đường đi
(Path length):
- Chiề u dà i đ ường đi của nút x: là số cá c cạ nh đi từ nút gốc đế n nút x.
Ví dụ
: Trong hì nh 5.1:
Nút gốc A có chiề u dà i đ ường đi là 1
Nút B, C, D có chiề u dà i đ ường đi là 2
Tổng quá t
: một nút tạ i mức i có chiề u dà i đ ường đi là i
- Chiề u dà i đ ường đi của câ y: là tổng của cá c chiề u dà i đường đi của tấ t cả
cá c nút trong câ y.
Ví dụ
: Chiề u dà i đ ường đi của câ y trong hì nh 5.1 là 31.
Chiề u dà i đ ường đi trung bì nh của câ y:
n/)i.
n
(
P
i
ii
=
trong đó n
i
là số cá c nút ở mức i và n là tổng số cá c nút trong câ y.
I.2. Cách biể u diễ n cây
: để biể u diễ n 1 câ y, ta có nhiề u cá ch như biể u diễ n
bằ ng đồ thị,bằ ng giả n đồ, bằ ng chỉ số.. Nhưng thông thường, ta hay dùng dạ ng
đồ thị để biểu diễn 1 câ y như hì nh 5.1
I.3. Biể u diễ n thứ tự các nút trong cây
:
Kỹ thuật lập trì nh
108
Một câ y thường tổ chức cá c nút theo một thứ tự nhấ t định că n cứ và o một
nội dung gọi là khóa của cá c nút. Có thể tổ chức câ y có khóa tă ng dầ n theo mức
từ trá i qua phả i như ví dụ sau :
1
2 3
4
Root
76 8
5
9
ROOT
%1%2%3%4%5%6%7%8%9
Như vậ y khi duyệ t lạ i câ y theo mức
tă ng dầ n và từ trá i qua phả i ta sẽ lạ i
có đ ược thứ tự cá c nút như trê n.
Hì nh 5.4. Câ y có thứ tự tă ng dầ n theo mức từ trá i qua phả i
II. Cây nhị phân
(Binary tree)
II.1. Định nghĩ a
:
1. Cây nhị phân là câ y có bậ c bằ ng 2, tức là số nút con tối đa của một nút
bấ t kỳ trong câ y là 2.
Câ y nhị phâ n có thể là một câ y rỗng (không có nút nà o) hoặ c câ y chỉ có
một nút, hoặ c câ y chỉ có cá c nút con bê n trá i (Left Child) hoặ c nút con bê n phả i
(Right Child) hoặ c cả hai.
Ví dụ
: Hì nh 5.4 là câ y nhị phâ n.
2. Các cây nhị phân đặc biệ t:
- Câ y nhị phâ n đúng
: Một câ y nhị phâ n đ ược gọi là câ y nhị phâ n đúng nế u
nút gốc và tấ t cả cá c nút trung gian đề u có 2 nút con.
A
B
D E
G Y
C
X F
H I
Hì nh 5.5. Câ y nhị phâ n đúng
Kỹ thuật lập trì nh
109
Ghi chú: nế u câ y nhị phâ n đúng có n nút lá thì câ y nà y sẽ có tấ t cả 2n-1 nút.
- Câ y nhị phâ n đầ y
: Một câ y nhị phâ n gọi là câ y nhị phâ n đầ y với chiề u cao
d thì :
. Nó phả i là câ y nhị phâ n đúng và
. Tấ t cả cá c nút lá đề u có mức là d.
Hì nh 5.5 không phả i là câ y nhị phâ n đầ y
A
B
D
H
I
E
J K
C
F
L M
G
N O
Hì nh 5.6. Câ y nhị phâ n đầ y.
Ghi chú
: Câ y nhị phâ n đầ y là câ y nhị phâ n có số nút tối đa ở mỗi mức.
- Câ y nhị phâ n tì m kiế m
(Binary Search Tree): Một câ y nhị phâ n gọi là câ y
nhị phâ n tì m kiế m nế u và chỉ nế u đối với mọi nút của câ y thì khóa của một nút
bấ t kỳ phả i lớn hơn khóa của tấ t cả cá c nút trong câ y con bê n trá i của nó và phả i
nhỏ hơn khóa của tấ t cả cá c nút trong câ y con bê n phả i của nó.
Ví dụ
:
8
7 9
3
12
11
102
1
5
4 6
k
1
<k
1
<k
1
Hì nh 5.7. Câ y nhị phâ n tì m kiế m (BST)
Kỹ thuật lập trì nh
110
- Câ y nhị phâ n câ n bằ ng (AVL): Một câ y nhị phâ n đ ược gọi là câ y nhị phâ n
câ n bằ ng nế u và chỉ nế u đối với mọi nút của câ y thì chiề u cao của câ y con bê n
trá i và chiề u cao của câ y con bê n phả i hơn kém nhau nhiề u nhấ t là 1. (Theo
Adelson-Velski và Landis).
A
C
E
F
B
D
G
I J
H
Hì nh 5.8. Câ y nhị phâ n câ n bằ ng
- Câ y nhị phâ n câ n bằ ng hoà n toà n
: Một câ y nhị phâ n đ ược gọi là câ y nhị
phâ n câ n bằ ng hoà n toà n nế u và chỉ nế u đối với mọi nút của câ y thì số nút của
câ y con bê n trá i và số nút của câ y con bê n phả i hơn kém nhau nhiề u nhấ t là 1.
A
C
E
F
B
D
I
H
E
H
Hì nh5.9. Câ y nhị phâ n câ n bằ ng hoà n toà n
3. Các phép duyệ t cây nhị phân
(Traverse)
: là quá trì nh đi qua cá c nút
đúng một lầ n. Khi duyệ t câ y, ta thường dùng 3 cá ch duyệ t cơ bả n sau :
' Preorder - Tiề n tự (NLR) duyệ t qua nút gốc trước, sau đó đi qua câ y con
bê n trá i lạ i á p dụng Preorder cho câ y con bê n trá i. Cuối cùng qua câ y con bê n
phả i, á p dụng Preorder cho câ y con bê n phả i.
Ví dụ
: Theo câ y nhị phâ n 5.4, ta có:
ROOT % 1 % 2 % 3 % 4 % 6 % 7 % 5 % 8 % 9
'Inorder - Trung tự (LNR) : qua câ y con bê n trá i duyệ t trước (theo thứ tự
LNR), sau đó thă m nút gốc. Cuối cùng qua câ y con bê n phả i (theo thứ tự LNR)
Ví dụ
: Theo câ y nhị phâ n 5.4, ta có:
ROOT % 2 % 1 % 6 % 4 % 7 % 3 % 8 % 5 % 9
'Postorder - Hậ u tự (LRN) : qua câ y con bê n trá i duyệ t trước (theo thứ tự
LRN), sau đó qua câ y con bê n phả i (theo thứ tự LRN). Cuối cùng thă m nút gốc.
Ví dụ
: Theo câ y nhị phâ n 5.4, ta có:
ROOT % 2 % 6 % 7 % 4 % 8 % 9 % 5 % 3 % 1
Kỹ thuật lập trì nh
111
Ghi chú : Đối với câ y ta có thể tổ chức thứ tự theo khóa là một nội dung
của nút hoặ c ta đặ t thê m 1 field gọi là khóa của nút .
II.2. Các phép toán trê n cây nhị phân
:
- Khai báo
: Để tổ chức dữ liệ u theo câ y nhị phâ n, ta có thể dùng một nội
dung của dữ liệ u để là m khóa sắ p xế p và tổ chức câ y theo nhiề u cá ch khá c nhau.
Nhưng thông thường để thuậ n tiệ n cho việ c tì m kiế m và thực hiệ n cá c phép toá n
khá c trê n câ y, người ta tạ o thê m một khóa riê ng trong cá c phầ n tử và tạ o ra câ y
nhị phâ n tì m kiế m.
Để khai bá o biế n tree quả n lý một câ y nhị phâ n, với nội dung info chứa số
nguyê n, ta khai bá o như sau:
struct nodetype
{
int key;
int info;
struct nodetype *left;
struct nodetype *right;
};
typedef struct nodetype *NODEPTR;
NODEPTR tree;
1. Tạo cây:
a. Khởi tạ o câ y
(Initialize): dùng để khởi động câ y nhị phâ n, cho chương
trì nh hiể u là hiệ n tạ i câ y nhị phâ n rỗng.
void Initialize(NODEPTR &root)
{
root = NULL;
}
Lời gọi hà m
: Initialize(tree);
b. Cấ p phá t vùng nhớ
(New_Node): cấ p phá t một nút cho câ y nhị phâ n.
Hà m New_Node nà y trả về địa chỉ của nút vừa cấ p phá t.
NODEPTR New_Node(void)
{
NODEPTR p;
p = (NODEPTR)malloc(sizeof(struct nodetype));
return(p);
}
Lời gọi hà m
: p= New_Node();
Kỹ thuật lập trì nh
112
c. Tạ o câ y BST (Create_Tree): Trong giả i thuậ t tạ o câ y BST, ta có dùng
hà m Insert.
Hà m Insert
: dùng phương phá p đệ qui thê m nút có khóa x, nội dung a và o
câ y có nút gốc root . Câ y nhị phâ n tạ o đ ược qua giả i thuậ t Create_Tree là câ y
nhị phâ n tì m kiế m (BST).
void Insert(NODEPTR root, int x, int a)
{ NODEPTR p;
if(x == root->key) // khóa bị trùng, dừng chương trì nh
{
printf("bi trung khoa, khong them nut nay duoc");
return;
}
if(x < root->info && root->left == NULL) // điề u kiệ n dừng giả i thuậ t đệ qui
{
p = New_Node(); // cấ p phá t vùng nhớ
p->key =x;
p->info = a;
p->left = NULL;
p->right = NULL;
root->left=p;
return;
}
if(x > root->info && root->right == NULL) //điề u kiệ n dừng giả i thuậ t đệ qui
{
p = New_Node();
p->key =x;
p->info = a;
p->left = NULL;
p->right = NULL;
root->right=p ;
return;
}
if(x < root->info) // bước đệ qui
Insert(root->left, x,a); // gọi đệ qui qua nhá nh trá i
else
Insert(root->right, x,a); // gọi đệ qui qua nhá nh phả i
}
Kỹ thuật lập trì nh
113
void Create_Tree(NODEPTR &root)
{ int khoa, noidung;
char so[10];
NODEPTR p;
do
{ printf("Nhap khoa :");
gets(so) ;
khoa = atoi(so);
if (khoa !=0)
{ printf("Nhap noi dung :");
gets(so) ;
noidung = atoi(so);
if (root==NULL)
{ p = New_Node();
p->key = khoa;
p->info = noidung;
p->left = NULL;
p->right = NULL;
root =p;
}
else Insert(root,khoa,noidung);
}
} while (khoa!=0); // khóa =0 thì dừng nhậ p
}
Ghi chú
: Để tạ o câ y nhị phâ n do biế n tree quả n lý, ta gọi:
Create_Tree(tree);
2. Cập nhật cây:
a. Giả i phóng vùng nhớ
(Free_Node): giả i phóng vùng nhớ mà p đang trỏ đế n.
void Free_Node(NODEPTR p)
{
free(p);
}
Lời gọi hà m
: Free_Node (p);
b. Kiể m tra câ y nhị phâ n rỗng hay không
(Empty): hà m Empty trả về
TRUE nế u câ y nhị phâ n rỗng, và ngược lạ i.
int Empty(NODEPTR root)
return(root == NULL ? TRUE : FALSE);
}
Kỹ thuật lập trì nh
114
Lời gọi hà m: Empty(tree)
c. Hủy bỏ một nút trong câ y nhị phâ n BST
(Remove):
Xóa nút có khóa là x trong câ y nhị phâ n tì m kiế m sao cho sau khi xóa thì
câ y nhị phâ n vẫ n là câ y nhị phâ n tì m kiế m. Ta có 3 trường hợp :
-
Trường hợp 1
: nút p cầ n xóa là nút lá . Việ c xóa nút p chỉ đơn giả n là hủy
nút p
p1
p
p1
p1
p
p1
-
Trường hợp 2
: Nút p cầ n xóa có 1 câ y con, thì ta cho rp chỉ tới nút p. Sau
đó, ta tạ o liê n kế t từ nút cha của p tới nút con của rp, cuối cùng hủy nút p.
10
5
3
15
12
20
2
4
p
xoựa nuựt p
10
3 15
12
20
2
4
rp
Hì nh 5.10. Xóa nút p trong trường hợp nút nà y có 1 câ y con bê n trá i.
2
10
5
3
15
4
20
18 25
rp
p
xoựa nuựt p
10
5
3
20
18 25
2 4
Hì nh 5.11. Xóa nút p trong trường hợp nút nà y có 1 câ y con bê n phả i.
-
Trường hợp 3
: Nút p cầ n xóa có 2 câ y con. Ta cho rp chỉ tới nút p. Do tí nh
chấ t nút cực trá i của câ y con bê n phả i của p có khóa vừa lớn hơn khóa của p,
nê n để loạ i p thì ta sẽ cho r chỉ tới nút cực trá i đó. Sau đó, ta sao chép nội dung