Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (206.92 KB, 70 trang )
<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1></div>
<span class='text_page_counter'>(2)</span><div class='page_container' data-page=2>
2
• Định nghĩa:
• Rỡng là 1 cây
• T1 , T2 , ……Tm là cây thi
là cây (m-phân)
• T1 , T2 , ……Tm gọi là cây con của cây T
T
T<sub>m</sub>
T<sub>2</sub>
• Ví dụ
– Cây thư mục trong hệ điều hành
– Cây gia phả của 1 dòng họ
– Cây biểu thức: a-b+c*d/e
+
- /
4
• R là cha của U, O, P
• U, O, P là con của R
• Q, R là đỉnh trước của A.
• A là đỉnh sau của Q, R
• T, Y, U, O, A là các nút lá (khơng có con)
• Q là nút gốc
Q
E R
w
Y
T U O P
A
mức 1
mức 2
mức 3
• Phép duyệt: Đưa ra tất cả các nút theo
mợt thứ tự nào đó, mỡi nút 1 lần
– Ví dụ: Tim kiếm một file hay một folder trong
cây thư mục
• Phổ biến:
– Duyệt theo bề sâu (Depth First Search - DFS)
– Duyệt theo bề rộng (Breadth First Search -
6
• Là cây bao gờm các nút, mỡi nút có tới đa 2 cây
con:
– Cây con bên trái (Left)
– Cây con bên phải (Right)
• Mơ tả cấu trúc:
<i><b>typedef struct nodet {</b></i>
<i><b>elem data;</b></i>
<i><b>struct nodet *left, *right;</b></i>
<i><b>} node;</b></i>
<i>• Duyệt tiền tự (Preorder Search – NLR)</i>
<i>– Thăm nút gốc (Node)</i>
<i>– Duyệt cây con bên trái (Left)</i>
<i>– Duyệt cây con bên phải (Right) </i>
<i>• Duyệt trung tự (Inorder Search – LNR)</i>
(tương tự)
8
• NLR: QWTYRUPA
• LNR: TWYQURAP
• LRN: TYWUAPRQ
Q
R
w
Y
T U P
<i><b>int sonut(tree t)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
10
<i><b>int h(tree t)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>return 1 + max(h(t->left), h(t->right));</b></i>
<i><b>}</b></i>
<i><b>void nhap(tree &t)</b></i>
<i><b>{</b></i>
<i><b>int x;</b></i>
<i><b>cin>>x;</b></i>
<i><b>if (x>0)</b></i>
<i><b>{</b></i>
<i><b>t = new node;</b></i>
<i><b>t->data = x;</b></i>
<i><b>else</b></i>
<i><b>t = NULL;</b></i>
• Với cây trên dữ liệu nhập:
<i>7 2 4 0 0 5 0 0 6 </i>
<i> 3 0 0 9 8 0 </i>
<i> 0 0</i>
7
6
2
5
4 3 9
12
<i><b>void incay(tree t, int m=1)</b></i>
<i><b>{</b></i>
<i><b>if (t!=NULL)</b></i>
<i><b>{</b></i>
<i><b>incay(t->left, m+1);</b></i>
<i><b>cout<<endl<<setw(4*m)<<t->data;</b></i>
<i><b>incay(t->right, m+1);</b></i>
<i><b>void xoacay(tree &t)</b></i>
<i><b>{</b></i>
<i><b>if (t!=NULL)</b></i>
<i><b>{</b></i>
<i><b>xoacay(t->left);</b></i>
<i><b>xoacay(t->right);</b></i>
<i><b>delete t;</b></i>
14
<i><b>int sonutla(tree t)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>if (t->left==NULL && t->right==NULL)</b></i>
<i><b>int sonut1(tree t)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>if ((t->left!=NULL) &&( t->right==NULL))</b></i>
<i><b>return 1+sonut1(t->left);</b></i>
<i><b>if ((t->left==NULL) &&( t->right!=NULL))</b></i>
<i><b>return 1+sonut1(t->right);</b></i>
16
<i><b>int sonut1(tree t)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>if ((t->left!=NULL && t->right==NULL)||</b></i>
<i><b> (t->left==NULL && t->right!=NULL)) </b></i>
<i><b>return 1+sonut1(t->left) +sonut1(t->right);</b></i>
<i><b>return sonut1(t->left)+sonut1(t->right);</b></i>
<i><b>int sonut1(tree t)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>if ((t->left==NULL) ^( t->right==NULL))</b></i>
<i><b>return 1+sonut1(t->left)+sonut1(t->right);</b></i>
<i><b>return sonut1(t->left)+sonut1(t->right);</b></i>
18
<i><b>int sonuttrg(tree t)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>if (t->left==NULL && t->right==NULL)</b></i>
<i><b>return 0;</b></i>
<i><b>void NLR(tree t, int &sn, int &tg)</b></i>
<i><b>{</b></i>
<i><b>if (t!=NULL)</b></i>
<i><b>tg+=t->data;</b></i>
<i><b>sn++;</b></i>
<i><b>NLR(t->left, sn, tg);</b></i>
<i><b>NLR(t->right, sn, tg);</b></i>
<i><b>}</b></i>
<i><b>}</b></i>
<i><b>float tbc(tree t)</b></i>
<i><b>{</b></i>
<i><b>int sn, tg;</b></i>
<i><b>sn = tg = 0;</b></i>
<i><b>NLR(t, sn, tg);</b></i>
20
• Đếm sớ nút trên mức thứ k
• Đếm sớ nút trên mức >= k
• Đếm số nút trên mức <= k
<i><b>int muccl(tree t, int m=1)</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>return m%2 +muccl(t->left, m+1) +</b></i>
<i><b>muccl(t->right, m+1);</b></i>
<i><b>}</b></i>
<i><b>Gọi hàm:</b></i>
<i><b>cout<<“Số nút trên mức lẻ =“<<muccl(t);</b></i>
22
<i><b>int nutk(tree t, int k)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL) return 0;</b></i>
<i><b>if (k>1)</b></i>
<i><b>return nutk(t->left,k-1)+nutk(t->right, k-1);</b></i>
<i><b>return 1;</b></i>
void nlr(tree t, int k, int &sn, int &tg)
{
if (t!=NULL)
{
nlr(t->left, k-1, sn, tg);
nlr(t->right, k-1, sn, tg);
}
else
{
sn++;
tg +=t->data);
}
}
}
<i><b>float tbc(tree t, int k)</b></i>
<i><b>{</b></i>
<i><b>int sn, tg;</b></i>
<i><b>sn = tg = 0;</b></i>
<i><b>nlr(t, k, sn, tg);</b></i>
24
void nlr(tree t, int k, int &sn, int &tg)
{
if (t!=NULL)
{
sn++;
tg +=t->data);
nlr(t->left, k-1, sn, tg);
nlr(t->right, k-1, sn, tg);
}
}
}
<i><b>float tbc(tree t, int k)</b></i>
<i><b>{</b></i>
<i><b>int sn, tg;</b></i>
<i><b>sn = tg = 0;</b></i>
<i><b>nlr(t, k, sn, tg);</b></i>
<i><b>if (sn == 0) return </b></i>
<i><b>0.;</b></i>
void nlr(tree t, int k, int &sn, int
&tg)
{
if (t!=NULL)
{
if (k<=1)
{
sn++;
tg +=t->data);
nlr(t->left, k-1, sn, tg);
nlr(t->right, k-1, sn,
tg);
}
}
<i><b>float tbc(tree t, int k)</b></i>
<i><b>{</b></i>
<i><b>int sn, tg;</b></i>
<i><b>sn = tg = 0;</b></i>
<i><b>nlr(t, k, sn, tg);</b></i>
<i><b>if (sn == 0) return </b></i>
<i><b>0.;</b></i>
26
• Hay còn gọi là dụt theo mức
• Sử dụng hàng đợi: Tuần tự từ
mức thấp đến cao, từ trái qua
phải
• Với cây trên ta có thứ tự các
nút được duyệt lần lượt:
Q W R T Y U P A
SV cài đặt như bài tập
Q
R
w
Y
T U P
<i>1. Khởi tạo hàng đợi q rỗng</i>
<i>2. M=0; p=NULL;</i>
<i>3. Nếu t!=NULL</i>
• <i>Đưa p vào q</i>
• <i>Đưa t vào q</i>
<i>4. Khi q!=rỗng</i>
• <i>Lấy p ra khỏi q</i>
• <i><sub>Nếu p==NULL</sub></i>
<i><sub>Nếu q!=rỗng</sub></i>
• <i>M = M+1;</i>
• <i>Đưa p vào q</i>
• <i>//Xử lý</i>
• <i>Ngược lại</i>
<i><sub>Xử lý p->data</sub></i>
28
• Ý nghĩa: Phục vụ tim kiếm nhị phân trên cấu
trúc đợng
• Định nghĩa: Là cây nhị phân thỏa điều kiện mọi
nút đều có khóa
7
11
3
5
1 9 15
30
• Thêm 12
•
20
10
15
5
30
25 40
35
12<
12>
12<
12
<i><b>void inserttree(tree &t, elem x)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL)</b></i>
<i><b>{</b></i>
<i><b>t = new node;</b></i>
<i><b>t->data = x;</b></i>
32
<i><b>t = NULL;</b></i>
<i><b>do {</b></i>
<i><b>cin>>x;</b></i>
<i><b>if (x>0)</b></i>
• Xóa 15
20
10
15
5
30
25 40
35
15<
15>
15=
34
• Xóa 20
20
10
15
5
30
25 40
<i><b>void deletetree(tree &t, elem x)</b></i>
<i><b>{</b></i>
<i><b> tree q = t;</b></i>
<i><b> if (t->right==NULL)</b></i>
<i><b>t = t->left;</b></i>
<i><b> else</b></i>
<i><b>if (t->left==NULL)</b></i>
<i><b> t = t->right;</b></i>
<i><b>else</b></i>
36
Tim phần tử thay thế (phần tử lớn nhất)
<i><b>void del(tree &r, tree &q)</b></i>
<i><b>{</b></i>
<i><b>if (r->right!=NULL)</b></i>
<i><b>del(r->right, q);</b></i>
<i><b>else</b></i>
<i><b>q->data = r->data;</b></i>
<i><b>q = r;</b></i>
38
<i><b>tree searchtree(tree t, elem x)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL)</b></i>
<i><b>return NULL;</b></i>
<i><b>if (x<t->data)</b></i>
<i><b>return searchtree(t->left, x);</b></i>
<i><b>if (x>t->data)</b></i>
<i><b> return searchtree (t->right, x);</b></i>
<i><b>return t;</b></i>
<i><b>tree cuttree(tree &t, elem x)</b></i>
<i><b>{</b></i>
<i><b>if (t==NULL)</b></i>
<i><b>return NULL;</b></i>
<i><b>if (x<t->data)</b></i>
<i><b>return cuttree (t->left, x);</b></i>
<i><b> if (x>t->data)</b></i>
<i><b> return cuttree (t->right, x);</b></i>
<i><b>{</b></i>
40
<i><b>void ink(tree t, int &k)</b></i>
<i><b>{</b></i>
<i><b>if (t!=NULL)</b></i>
<i><b>{</b></i>
<i><b>if (k>0)</b></i>
<i><b>ink(t->right, k);</b></i>
<i><b>if (k>0)</b></i>
<i><b>{</b></i>
<i><b>cout<<setw(4)<<t->data;</b></i>
<i><b>k--;</b></i>
<i><b>}</b></i>
<i><b>if (k>0)</b></i>
<i><b>ink(t->left, k);</b></i>
<i><b>}</b></i>
42
• Đưa vào cây:1, 2, 3, …, n
1
2
3
44
46
• Tương tự như BST, tuy nhiên mỗi node cần bổ
<i><b>sung một vùng bal (balance), ghi nhận trạng </b></i>
thái cân bằng tại node đó:
<i><b>typedef struct nodet {</b></i>
<i><b>elem data;</b></i>
<i><b>struct nodet *left, *right;</b></i>
<i><b>int bal;</b></i>
<i><b>} node;</b></i>
48
• Tại p có 3 trường hợp:
p->bal = 1 p->bal = 0 p->bal = -1
• Thêm vào làm cho h<sub>R</sub> tăng
hoặc xóa làm cho hL giảm
Đặt p1 = p->right
phép quay:
<i><b> p->right=p1->left</b></i>
<i><b> p1->left =p</b></i>
p
p1 p
50
• Thêm vào làm cho hR tăng
hoặc xóa làm cho hL giảm
phép quay đơn:
<i><b> p->right=p1->left</b></i>
<i><b> p1->left =p</b></i>
<i><b>p->bal =0</b></i>
<i><b>p1->bal=0</b></i>
<i><b>p = p1</b></i>
p
p1 p
• Chỉ xảy ra khi xóa làm cho h<sub>L</sub> giảm
phép quay đơn:
<i><b> p->right=p1->left</b></i>
<i><b> p1->left =p</b></i>
<i><b>p->bal =1</b></i>
<i><b>p1->bal=-1</b></i>
p
p1 p
52
• Khơng sử dụng phép quay đơn được vi sẽ mất cân
bằng
phép quay đơn:
<i><b> p->right=p1->left</b></i>
<i><b> p1->left =p</b></i>
p1
p
p
• Đặt p2 = p1->left
Sử dụng phép quay kép
<i> </i> <i><b>p->right=p2->left</b></i>
<i><b> p2->left=p</b></i>
<i><b> p1->left=p2->right</b></i>
<i><b> p2->right=p1</b></i>
<i><b>p->bal=(p2->bal==1? -1: 0)</b></i>
<i><b>p1->bal=(p2->bal==-1? 1: 0)</b></i>
p
p1
p2
p2
54
• Trường hợp này đới xứng với trường hợp
a), chính vi vậy ta chỉ cần thay
– left thành right và ngược lại
• Tương tự như BST, tuy nhiên sau khi
chèn cây sẽ tăng độ cao, sử dụng biến h
để ghi nhận cây có tăng đợ cao hay
56
• Thêm lần lượt 3, 5 và 7
3 1
5 <sub>7</sub>
3 1
5 0
0
5 0
7 0
3
0
Thêm 7
Mất cân bằng tại 3
Sử dụng quay đơn …và cân bằng
7
3 1
5 1
Thêm 12, 10
5 1
7 1
3
0
12 0
10 0
Thêm 10
5 1
7 1
3
0
12 -1
10 0
58
• Thêm 11
5 1
10 0/1
3
0
12 0/-1
7
0
11 0
-1
5
0
0 11 0
• Thêm 8, 9 ?
-1
5
0
10
3
0
12
7
0 11 0
60
<i><b>void insertAVL(AVLtree &p, elem </b></i>
<i><b>x, int &h)</b></i>
<i><b>if (p==NULL)</b></i>
<i><b>{</b></i>
<i><b>p = new node;</b></i>
<i><b>p->data = x;</b></i>
<i><b>p->left = p->right = NULL;</b></i>
<i><b>p->bal=0;</b></i>
<i><b>h=1;</b></i> <i><b>//true</b></i>
<i><b>}</b></i>
<i><b>else</b></i>
<i><b>if (x<p->data)</b></i>
<i><b>{</b></i>
<i><b>insertAVL(p->left, x, h);</b></i>
<i><b>if (h) </b><b>Xem lại cân bằng trái tại p;</b></i>
<i><b>}</b></i>
<i><b>else</b></i>
<i><b>if (x>p->data)</b></i>
<i><b>{</b></i>
<i><b>insertAVL(p->right, x, h);</b></i>
<i><b> </b></i> <i><b>if (h) </b><b>Xem lại cân bằng </b></i>
<i><b>phải tại p;</b></i>
<i><b>}</b></i>
<i><b>else</b></i>
<i><b>switch (p->bal)</b></i>
<i><b>{</b></i>
<i><b>case 1: p->bal = 0; h = 0; break;</b></i>
<i><b>case 0: p->bal = -1; break;</b></i>
<i><b>case -1:</b></i>
<i><b>{</b></i> <i><b>AVLtree p1 = p->left;</b></i>
<i><b>if (p1->bal ==-1)</b></i>
<i><b>{</b></i>
<i><b> p->left = p1->right;</b></i>
<i><b> p1->right = p;</b></i>
<i><b> p->bal = 0;</b></i>
<i><b> p = p1; //p->bal =0; h=0</b></i>
<i><b>}</b></i>
<i><b>else</b></i>
<i><b>{</b></i>
<i><b>AVLtree p2 = p1->right;</b></i>
<i><b>p->left = p2->right;</b></i>
<i><b>p2->right = p;</b></i>
<i><b>p1->right = p2->left;</b></i>
<i><b>p2->left = p1;</b></i>
<i><b>p->bal = (p2->bal==-1?1:0);</b></i>
<i><b>p1->bal = (p2->bal==1?-1:0);</b></i>
<i><b>p = p2; //p->bal =0; h=0</b></i>
<i><b>}</b></i>
<i><b>p->bal = 0;</b></i>
<i><b>h = 0;</b></i>
62
• Trường hợp này đới xứng với trường hợp
xem lại thế cân bằng trái, chính vi vậy ta
chỉ cần thay
– left thành right và ngược lại
– 1 thành -1 và ngược lại
0 11 0
1
20
25
-1
30
23 0
35
27 0
0
6
0 9 0
3
-1
64
5
0
10
12
7
0 11 0
1
20
23
1
25
30
27 0
0
6
0 9 0
3
-1
0 11 0
1
20
25
-1
30
23 0
35
-1
6
0 9 0
3
-1
66
• Mất cân bằng tại 20
20
23
1
25
30
0
-1
5
-1
10
12
7
0 11 0
1
6
0 9 0
3
0
10
20
12
-1
0
5 1
7
0
6
0 9
3
0
23
0
25
30
0
68
<i><b>void deleteAVL(AVLtree &p, elem x, int &h)</b></i>
<i><b>{</b></i>
<i><b>if (p==NULL)</b></i>
<i><b> h = 0;</b></i>
<i><b>else</b></i>
<i><b> if (x<p->data)</b></i>
<i><b> {</b></i>
<i><b> deleteAVL(p->left, x, h);</b></i>
<i><b> if (h) </b><b>Xem lại thê cân bằng trái tại p</b></i>
<i><b> }</b></i>
<i><b> else</b></i>
<i><b>if (x>p->data)</b></i>
<i><b> deleteAVL(p->right, x, h);</b></i>
<i><b> if (h)</b></i>
<i><b>Xem lại thê cân bằng phải tại p</b></i>
<i><b>}</b></i>
<i><b>else</b></i>
<i><b>{</b></i>
<i><b> AVLtree q = p;</b></i>
<i><b> if (p->right==NULL)</b></i>
<i><b> {</b></i>
<i><b>p = p->left;</b></i>
<i><b>h = 1;</b></i>
<i><b> }</b></i>
<i><b> else</b></i>
<i><b>if (p->left==NULL)</b></i>
<i><b>{</b></i>
<i><b> p = p->right;</b></i>
<i><b> h = 1;</b></i>
<i><b>}</b></i>
<i><b> del(p->left, q, h);</b></i>
<i><b> if (h)</b></i>
<i><b> </b><b>Xem lại thê cân bằng trái tại p</b><b> </b></i>
<i><b> }</b></i>
<i><b> delete q;</b></i>
<i><b>}</b></i>
<i><b>void del(AVLtree &r, AVLtree &q, int &h)</b></i>
<i><b>{</b></i>
<i><b>if (r->right!=NULL)</b></i>
<i><b>{</b></i>
<i><b>del(r->right, q, h);</b></i>
<i><b>if (h) </b><b>Xem lại thê cân bằng phải tại r</b></i>
<i><b>}</b></i>
<i><b>else</b></i>
<i><b>{</b></i>
<i><b>q->data = r->data;</b></i>
<i><b>q = r;</b></i>
<i><b>r = r->left;</b></i>
<i><b>h = 1;</b></i>
70
• Minh họa quá trinh hinh thành cây AVL khi
thêm lần lượt các giá trị sau vào cây (chỉ rõ
phép quay- nếu có):