You are on page 1of 246

CẤU TRÚC DỮ LIỆU

VÀ THUẬT TOÁN

CHƯƠNG 1: CÁC KHÁI NIỆM


CƠ BẢN
NỘI DUNG

1.1. Ví dụ mở đầu

1.2. Thuật toán và độ phức tạp

1.3. Ký hiệu tiệm cận

1.4. Giả ngôn ngữ

1.5. Một số kĩ thuật phân tích thuật toán

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ mở đầu

• Bài toán tìm dãy con lớn nhất:


Cho dãy số
a1, a2, … , an
Dãy số ai, ai+1 , …, aj với 1 ≤ i ≤ j ≤ n được gọi là dãy con của dãy
đã cho và ∑jk=i ak được gọi là trọng lượng của dãy con này
Bài toán đặt ra là: Hãy tìm trọng lượng lớn nhất của các dãy con, tức
là tìm cực đại giá trị ∑jk=i ak. Để đơn giản ta gọi dãy con có trọng
lượng lớn nhất là dãy con lớn nhất.

• Ví dụ: Nếu dãy đã cho là -2, 11, -4, 13, -5, 2 thì cần đưa ra
câu trả lời là 20 (là trọng lượng của dãy con 11, -4, 13)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán trực tiếp

• Thuật toán đơn giản đầu tiên có thể nghĩ để giải bài toán đặt ra
là: Duyệt tất cả các dãy con có thể

ai, ai+1 , …, aj với 1 ≤ i ≤ j ≤ n

và tính tổng của mỗi dãy con để tìm ra trọng lượng lớn nhất.

• Trước hết nhận thấy rằng, tổng số các dãy con có thể của dãy đã
cho là

C(n,2) + n = n2/2 + n/2 .

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán trực tiếp

• Thuật toán này có thể cài đặt trong đoạn chương trình sau:

int maxSum = 0;
for (int i=0; i<n; i++) {
for (int j=i; j<n; j++) {
int sum = 0;
for (int k=i; k<=j; k++)
sum += a[k];
if sum > maxSum
maxSum = sum;
}
}

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán trực tiếp

• Phân tích thuật toán: Ta sẽ tính số lượng phép cộng


mà thuật toán phải thực hiện, tức là đếm xem dòng lệnh
Sum += a[k]
phải thực hiện bao nhiêu lần. Số lượng phép cộng sẽ là
n 1 n 1 n 1 n 1
(n  i )( n  i  1)
 ( j  i  1)  (1  2  ...  (n  i))  
i  0 j i i 0 i 0 2
1 n 1  n 2 n  1  n(n  1)(2n  1) n(n  1) 
  k (k  1)    k   k    
2 k 1 2  k 1 k 1  2 6 2 
n3 n 2 n
  
6 2 3

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán nhanh hơn

• Để ý rằng tổng các số hạng từ i đến j có thể thu được


từ tổng của các số hạng từ i đến j-1 bởi 1 phép cộng, cụ
thể là ta có:
j j 1

 a[k ]  a[ j ]   a[k ]
k i k i

• Nhận xét này cho phép rút bớt vòng lặp for trong cùng.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán nhanh hơn

• Ta có thể cài đặt như sau

int maxSum = a[0];


for (int i=0; i<n; i++) {
int sum = 0;
for (int j=i; j<n; j++) {
sum += a[j];
if sum > maxSum
maxSum = sum;
}
}

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán nhanh hơn

• Phân tích thuật toán. Ta lại tính số lần thực hiện phép cộng
và thu được kết quả sau:
n 1
n2 n

i 0
(n  i )  n  (n  1)  ...  1  
2 2
• Để ý rằng số này là đúng bằng số lượng dãy con. Dường như
thuật toán thu được là rất tốt, vì ta phải xét mỗi dãy con đúng 1
lần.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• Ta còn có thể xây dựng thuật toán tốt hơn nữa! Ta sẽ sử


dụng kỹ thuật chia để trị. Kỹ thuật này bao gồm các
bước sau:
– Chia bài toán cần giải ra thành các bài toán con cùng dạng
– Giải mỗi bài toán con một cách đệ qui
– Tổ hợp lời giải của các bài toán con để thu được lời giải của bài toán
xuất phát.
• Áp dụng kỹ thuật này đối với bài toán tìm trọng lượng
lớn nhất của các dãy con: Ta chia dãy đã cho ra thành 2
dãy sử dụng phần tử ở chính giữa và thu được 2 dãy số
(gọi tắt là dãy bên trái và dãy bên phải) với độ dài giảm
đi một nửa.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• Để tổ hợp lời giải, nhận thấy rằng chỉ có thể xảy ra một
trong 3 trường hợp:
– Dãy con lớn nhất nằm ở dãy con bên trái (nửa trái)
– Dãy con lớn nhất nằm ở dãy con bên phải (nửa phải)
– Dãy con lớn nhất bắt đầu ở nửa trái và kết thúc ở nửa phải (giữa).
• Do đó, nếu ký hiệu trọng lượng của dãy con lớn nhất ở
nửa trái là wL, ở nửa phải là wR và ở giữa là wM thì
trọng lượng cần tìm sẽ là
max(wL, wR, wM).

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• Việc tìm trọng lượng của dãy con lớn nhất ở nửa trái
(wL) và nửa phải (wR) có thể thực hiện một cách đệ qui
• Để tìm trọng lượng wM của dãy con lớn nhất bắt đầu ở
nửa trái và kết thúc ở nửa phải ta thực hiện như sau:
– Tính trọng lượng của dãy con lớn nhất trong nửa trái kết
thúc ở điểm chia (wML) và
– Tính trọng lượng của dãy con lớn nhất trong nửa phải bắt
đầu ở điểm chia (wMR).
– Khi đó wM = wML + wMR.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• m – điểm chia của dãy trái, m+1 là điểm chia của dãy phải

a1, a2,…,am, am+1, am+2,…,an

Tính WML của dãy con Tính WMR của dãy con
lớn nhất trong nửa trái lớn nhất trong nửa phải
kết thúc tại am bắt đầu từ am+1

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• Để tính trọng lượng của dãy con lớn nhất ở nửa trái (từ
a[i] đến a[j]) kết thúc ở a[j] ta dùng thuật toán sau:

MaxLeft(a, i, j);
{
maxSum = -; sum = 0;
for (int k=j; k>=i; k--) {
sum = sum+a[k];
maxSum = max(sum, maxSum);
}
return maxSum;
}

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• Để tính trọng lượng của dãy con lớn nhất ở nửa phải (từ
a[i] đến a[j]) bắt đầu từ a[i] ta dùng thuật toán sau:

MaxRight(a, i, j);
{
maxSum = -; sum = 0;
for (int k=i; k<=j; k++){
sum = sum+a[k];
maxSum = max(sum, maxSum);
}
return maxSum;
}

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

Sơ đồ của thuật toán đệ qui có thể mô tả như sau:


MaxSub(a, i, j);
{
if (i = j) return a[i]
else
{ m = (i+j)/2;
wL = MaxSub(a, i, m);
wR = MaxSub(a, m+1, j);
wM = MaxLeft(a, i, m)+
MaxRight(a, m+1, j);
return max(wL, wR, wM);
}
}

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• Phân tích thuật toán:


Ta cần tính xem lệnh gọi MaxSub(a,1,n) để thực hiện thuật
toán đòi hỏi bao nhiêu phép cộng?
• Truớc hết nhận thấy MaxLeft và MaxRight đòi hỏi
n/2 + n/2 = n phép cộng
• Vì vậy, nếu gọi T(n) là số phép cộng cần tìm, ta có công thức
đệ qui sau:
0 n 1

T ( n)   n n n
T ( 2 )  T ( 2 )  n  2T ( 2 )  n n 1

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán đệ qui

• Ta khẳng định rằng T(2k) = k.2k. Ta chứng minh bằng qui nạp
• Cơ sở qui nạp: Nếu k=0 thì T(20) = T(1) = 0 = 0.20.
• Chuyển qui nạp: Nếu k>0, giả sử rằng T(2k-1) = (k-1)2k-1 là
đúng. Khi đó
T(2k) = 2T(2k-1)+2k = 2(k-1).2k-1 + 2k = k.2k.
• Quay lại với ký hiệu n, ta có
T(n) = n log n .
• Kết quả thu được là tốt hơn thuật toán thứ hai !

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
So sánh các thuật toán

• Cùng một bài toán ta đã đề xuất 3 thuật toán đòi hỏi số


lượng phép toán khác nhau và vì thế sẽ đòi hỏi thời gian
tính khác nhau.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán Quy hoạch động

Việc phát triển thuật toán dựa trên DP bao gồm 3 giai đoạn:
1. Phân rã: Chia bài toán cần giải thành những bài toán con nhỏ
hơn có cùng dạng với bài toán ban đầu.
2. Ghi nhận lời giải: Lưu trữ lời giải của các bài toán con vào một
bảng.
3. Tổng hợp lời giải: Lần lượt từ lời giải của các bài toán con
kích thước nhỏ hơn tìm cách xây dựng lời giải của bài toán
kích thước lớn hơn, cho đến khi thu được lời giải của bài toán
xuất phát (là bài toán con có kích thước lớn nhất).

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán QHĐ

• Phân r·. Gäi si lµ trọng lượng cña d·y con lín nhÊt
trong d·y a1, a2, ..., ai , i = 1, 2, ..., n.
Râ rµng sn lµ gi¸ trÞ cÇn t×m.
• Tæng hîp lêi gi¶i.
– Tr­íc hÕt, ta cã
s1 = a1.
– Gi¶ sö i > 1 vµ sk lµ ®· biÕt víi k = 1, 2, ..., i-1. Ta cÇn tÝnh si lµ
trọng lượng của d·y con lín nhÊt cña d·y

a1, a2, ..., ai-1, ai .

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán QHĐ

• Do dãy con lớn nhất của dãy này hoặc là có chứa phần tử ai hoặc là không
chứa phần tử ai, nên nó chỉ có thể là một trong hai dãy:
– Dãy con lớn nhất của dãy a1, a2, ..., ai-1
– Dãy con lớn nhất của dãy a1, a2, ..., ai kết thúc tại ai.
• Từ đó suy ra
si = max {si-1, ei}, i = 2, …, n.
trong đó ei là trọng lượng của dãy con lớn nhất của dãy a1, a2, ..., ai kết
thúc tại ai.
• Để tính ei, ta cũng có thể sử dụng công thức đệ qui sau:
– e1 = a1;
– ei = max {ai, ei-1 + ai}, i = 2, ..., n.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Thuật toán QHĐ
MaxSub(a);
{
smax = a[1]; (* smax – trọng lượng cña d·y con lín nhÊt *)
maxendhere = a[1]; (* maxendhere – trọng lượng của dãy con lớn nhất kết thúc tại a[i] *)
imax = 1; (* imax - vÞ trÝ kÕt thóc cña d·y con lín nhÊt *)
for i = 2 to n {
u = maxendhere + a[i];
v = a[i];
if (u > v) maxendhere = u
else maxendhere = v;
if (maxendhere > smax)then {
smax := maxendhere;
imax := i;
}
}
}
Phân tích thuật toán:
Dễ thấy số phép toán cộng phải thực hiện trong thuật toán (số lần thực
hiện câu lệnh u = maxendhere + a[i];) là n.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
NỘI DUNG

1.1. Ví dụ mở đầu

1.2. Thuật toán và độ phức tạp

1.3. Ký hiệu tiệm cận

1.4. Giả ngôn ngữ

1.5. Một số kĩ thuật phân tích thuật toán

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Khái niệm bài toán tính toán

• §Þnh nghÜa. Bµi to¸n tÝnh to¸n F lµ ¸nh x¹ tõ tËp c¸c x©u nhÞ ph©n ®é dµi
h÷u h¹n vµo tËp c¸c x©u nhÞ ph©n ®é dµi h÷u h¹n:
F : {0, 1}*  {0, 1}*.
• VÝ dô:
– Mçi sè nguyªn x ®Òu cã thÓ biÓu diÔn d­íi d¹ng x©u nhÞ ph©n lµ c¸ch
viÕt trong hÖ ®Õm nhÞ ph©n cña nã.
– HÖ ph­¬ng tr×nh tuyÕn tÝnh Ax = b cã thÓ biÓu diÔn d­íi d¹ng x©u lµ
ghÐp nèi cña c¸c x©u biÓu diÔn nhÞ ph©n cña c¸c thµnh phÇn cña ma
trËn A vµ vect¬ b.
– §a thøc mét biÕn P(x) = a0 + a1 x + ... + an xn hoµn toµn x¸c ®Þnh bëi
d·y sè n, a0, a1, ..., an, mµ ®Ó biÓu diÔn d·y sè nµy chóng ta cã thÓ sö
dông x©u nhÞ ph©n.
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Khái niệm thuật toán
• §Þnh nghÜa. Ta hiÓu thuËt to¸n gi¶i bµi to¸n ®Æt ra lµ mét thñ tôc x¸c ®Þnh
bao gåm mét d·y h÷u h¹n c¸c b­íc cÇn thùc hiÖn ®Ó thu ®­îc ®Çu ra cho
mét ®Çu vµo cho tr­íc cña bµi to¸n.
• ThuËt to¸n cã c¸c ®Æc tr­ng sau ®©y:
– §Çu vµo (Input): ThuËt to¸n nhËn d÷ liÖu vµo tõ mét tËp nµo ®ã.
– §Çu ra (Output): Víi mçi tËp c¸c d÷ liÖu ®Çu vµo, thuËt to¸n ®­a ra c¸c d÷ liÖu
t­¬ng øng víi lêi gi¶i cña bµi to¸n.
– ChÝnh x¸c (Precision): C¸c b­íc cña thuËt to¸n ®­îc m« t¶ chÝnh x¸c.
– H÷u h¹n (Finiteness): ThuËt to¸n cÇn ph¶i ®­a ®­îc ®Çu ra sau mét sè h÷u h¹n
(cã thÓ rÊt lín) b­íc víi mäi ®Çu vµo.
– §¬n trÞ (Uniqueness): C¸c kÕt qu¶ trung gian cña tõng b­íc thùc hiÖn thuËt
to¸n ®­îc x¸c ®Þnh mét c¸ch ®¬n trÞ vµ chØ phô thuéc vµo ®Çu vµo vµ c¸c kÕt qu¶
cña c¸c b­íc tr­íc.
– Tæng qu¸t (Generality): ThuËt to¸n cã thÓ ¸p dông ®Ó gi¶i mäi bµi to¸n cã d¹ng
®· cho.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Giải bài toán là gì?
What is Problem Solving?

• Problem solving
– Là quá trình đặt bài toán và phát triển chương trình máy tính để giải bài
toán đặt ra

• Lời giải bài toán bao gồm:


– Thuật toán (Algorithms)
• Algorithm: là dãy các bước cần thực hiện để từ dữ liệu vào (input) đưa ra
kết quả đầu ra (output) của bài toán trong thời gian hữu hạn.

– Cấu trúc dữ liệu:


• Cách tổ chức lưu trữ dữ liệu vào - ra

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Độ phức tạp của thuật toán

• Đánh giá độ phức tạp tính toán của thuật toán là đánh giá lượng
tài nguyên các loại mà thuật toán đòi hỏi sử dụng. Có hai loại tài
nguyên quan trọng đó là thời gian và bộ nhớ. Trong giáo trình
này ta đặc biệt quan tâm đến đánh giá thời gian cần thiết để thực
hiện thuật toán mà ta sẽ gọi là thời gian tính của thuật toán.
• Thời gian tính phụ thuộc vào dữ liệu vào.
• §Þnh nghÜa. Ta gäi kÝch th­íc d÷ liÖu ®Çu vµo (hay độ dài dữ
liệu vào) lµ sè bÝt cÇn thiÕt ®Ó biÓu diÔn nã.
• Ta sẽ tìm cách đánh giá thời gian tính của thuật toán bởi một hàm
của độ dài dữ liệu vào.
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Phép toán cơ bản

• Đo thời gian tính bằng đơn vị đo nào?

• §Þnh nghÜa. Ta gäi phÐp to¸n c¬ b¶n lµ phÐp to¸n cã


thÓ thùc hiÖn víi thêi gian bÞ chÆn bëi mét h»ng sè
kh«ng phô thuéc vµo kÝch th­íc d÷ liÖu.

• §Ó tÝnh to¸n thêi gian tÝnh cña thuËt to¸n ta sÏ ®Õm sè


phÐp to¸n c¬ b¶n mµ nã ph¶i thùc hiÖn.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Các loại thời gian tính

Chóng ta sÏ quan t©m ®Õn


– Thêi gian tèi thiÓu cÇn thiÕt ®Ó thùc hiÖn thuËt to¸n víi mäi bé d÷ liÖu ®Çu
vµo kÝch th­íc n. Thêi gian nh­ vËy sÏ ®­îc gäi lµ thêi gian tÝnh tèt nhÊt
cña thuËt to¸n víi ®Çu vµo kÝch th­íc n.

– Thêi gian nhiÒu nhÊt cÇn thiÕt ®Ó thùc hiÖn thuËt to¸n víi mäi bé d÷ liÖu
®Çu vµo kÝch th­íc n. Thêi gian nh­ vËy sÏ ®­îc gäi lµ thêi gian tÝnh tåi
nhÊt cña thuËt to¸n víi ®Çu vµo kÝch th­íc n.

– Thêi gian trung b×nh cÇn thiÕt ®Ó thùc hiÖn thuËt to¸n trªn tËp h÷u h¹n c¸c
®Çu vµo kÝch th­íc n. Thêi gian nh­ vËy sÏ ®­îc gäi lµ thêi gian tÝnh trung
b×nh cña thuËt to¸n.
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
NỘI DUNG

1.1. Ví dụ mở đầu

1.2. Giải bài toán và công nghệ phần mềm

1.3. Thuật toán và độ phức tạp

1.4. Ký hiệu tiệm cận

1.5. Giả ngôn ngữ

1.6. Một số kĩ thuật phân tích thuật toán

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ký hiệu tiệm cận
Asymptotic Notation

, O

• Được sử dụng để mô tả thời gian tính của thuật toán


• Thay vì nói chính xác thời gian tính, ta nói (n2)
• Được xác định đối với các hàm nhận giá trị nguyên
không âm
• Dùng để so sánh tốc độ tăng của hai hàm

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ký hiệu 

Đối với hàm g(n), ta ký hiệu (g(n)) là tập các hàm


(g(n)) = {f(n): tồn tại các hằng số c1, c2 và n0 sao cho
0  c1g(n)  f(n)  c2g(n), với mọi n  n0 }

Ta nói rằng g(n) là đánh giá tiệm


cận đúng cho f(n)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ

10n2 - 3n = (n2) ?
• Với giá trị nào của các hằng số n0, c1, và c2 thì bất đẳng
thức trong định nghĩa là đúng?

• Lấy c1 bé hơn hệ số của số hạng với số mũ cao nhất,


còn c2 lấy lớn hơn, ta có

n2 ≤ 10n2 – 3n ≤ 11n2, với mọi n ≥ 1.

• Đối với hàm đa thức: Để so sánh tốc độ tăng cần nhìn


vào số hạng với số mũ cao nhất
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ký hiệu O (đọc là ô lớn - big O)

Đối với hàm g(n) cho trước, ta ký hiệu O(g(n)) là tập các hàm
O(g(n)) = {f(n): tồn tại các hằng số dương c và n0 sao cho:
f(n)  cg(n) với mọi n  n0 }

Ta nói g(n) là cận trên tiệm cận của f(n)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ký hiệu 

Đối với hàm g(n) cho trước, ta ký hiệu (g(n)) là tập các hàm
(g(n)) = {f(n): tồn tại các hằng số dương c và n0 sao cho:
cg(n)  f(n) với mọi n  n0 }

Ta nói g(n) là cận dưới tiệm cận cho f(n)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Liên hệ giữa , , O

Đối với hai hàm bất kỳ g(n) và f(n),


f(n) = (g(n))
khi và chỉ khi
f(n) = O(g(n)) và f(n) = (g(n))
tức là
(g(n)) = O(g(n))  (g(n))

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Cách nói về thời gian tính

• Nói “Thời gian tính là O(f(n))” hiểu là: Đánh giá trong tình huống tồi
nhất (worst case) là O(f(n)). Thường nói: “Đánh giá thời gian tính
trong tình huống tồi nhất là O(f(n))”

• Nghĩa là thời gian tính trong tình huống tồi nhất được xác định
bởi một hàm nào đó g(n) (f(n))
• “Thời gian tính là (f(n))” hiểu là: Đánh giá trong tình huống tốt nhất
(best case) là (f(n)). Thường nói: “Đánh giá thời gian tính trong
tình huống tốt nhất là (f(n))”

– Nghĩa là thời gian tính trong tình huống tốt nhất được xác định
bởi một hàm nào đó g(n)  (f(n))

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ

• Sắp xếp chèn (Insertion sort) đòi hỏi thời gian


(n2) trong tình huống tồi nhất, vì thế bài toán sắp
xếp có thời gian là O(n2).

• Mọi thuật toán sắp xếp đều đòi hỏi duyệt qua tất
cả các phần tử, vì thế bài toán sắp xếp có thời gian
(n) trong tình huống tốt nhất.

• Trên thực tế, sử dụng (chẳng hạn) sắp xếp trộn


(merge sort), bài toán sắp xếp có thời gian
(n log n) trong tình huống tồi nhất.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ký hiệu tiệm cận trong các đẳng thức

• Được sử dụng để thay thế các biểu thức chứa các


toán hạng với tốc độ tăng chậm
• Ví dụ,
4n3 + 3n2 + 2n + 1 = 4n3 + 3n2 + (n)
= 4n3 + (n2) = (n3)
• Trong các đẳng thức, (f(n)) thay thế cho một hàm
nào đó g(n)  (f(n))
– Trong ví dụ trên, (n2) thay thế cho 3n2 + 2n + 1

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Sự tương tự giữa
so sánh các hàm số và so sánh các số

fg  ab

f (n) = O(g(n))  a  b

f (n) = (g(n))  a  b

f (n) = (g(n))  a = b

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Liên hệ với khái niệm giới hạn

• lim [f(n) / g(n)] = 0  f(n)  (g(n))


n

• lim [f(n) / g(n)] <   f(n)  (g(n))


n

• 0 < lim [f(n) / g(n)] <   f(n)  (g(n))


n

• 0 < lim [f(n) / g(n)]  f(n)  (g(n))


n

• lim [f(n) / g(n)] =   f(n)  (g(n))


n

• lim [f(n) / g(n)] không xác định không thể nói gì


n
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Các tính chất

• Truyền ứng (Transitivity)


f(n) = (g(n)) & g(n) = (h(n))  f(n) = (h(n))
f(n) = O(g(n)) & g(n) = O(h(n))  f(n) = O(h(n))
f(n) = (g(n)) & g(n) = (h(n))  f(n) = (h(n))
• Đối xứng (Symmetry)
f(n) = (g(n)) khi và chỉ khi g(n) = (f(n))
• Đối xứng chuyển vị (Transpose Symmetry)
f(n) = O(g(n)) khi và chỉ khi g(n) = (f(n))

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ

A B
• 5n2 + 100n 3n2 + 2

• log3(n2) log2(n3)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ

A B
• 5n2 + 100n 3n2 + 2 A  (B)
A  (n2), n2  (B)  A  (B)

• log3(n2) log2(n3)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ

A B
• 5n2 + 100n 3n2 + 2 A  (B)
A  (n2), n2  (B)  A  (B)

• log3(n2) log2(n3) A  (B)


logba = logca / logcb; A = 2lgn / lg3, B = 3lgn, A/B =2/(3lg3)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ

A B
• 5n2 + 100n 3n2 + 2 A  (B)
A  (n2), n2  (B)  A  (B)

• log3(n2) log2(n3) A  (B)


logba = logca / logcb; A = 2lgn / lg3, B = 3lgn, A/B =2/(3lg3)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ

• Với mỗi cặp hàm sau đây, hoặc f(n) = O(g(n)), f(n) = Ω(g(n)),
hoặc f(n) = Θ(g(n)). Hãy xác định quan hệ nào là đúng.
– f(n) = log n2; g(n) = log n + 5 f(n) =  (g(n))
– f(n) = n; g(n) = log n2 f(n) = (g(n))
– f(n) = log log n; g(n) = log n f(n) = O(g(n))
– f(n) = n; g(n) = log2 n f(n) = (g(n))
– f(n) = n log n + n; g(n) = log n f(n) = (g(n))
– f(n) = 10; g(n) = log 10 f(n) = (g(n))
– f(n) = 2n; g(n) = 10n2 f(n) = (g(n))
– f(n) = 2n; g(n) = 3n f(n) = O(g(n))

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Cận trên và cận dưới
Upper Bound and Lower Bound

• Định nghĩa (Upper Bound). Cho bài toán P, ta nói cận trên
cho thời gian tính của P là O(g(n)) nếu để giải P tồn tại thuật
toán giải với thời gian tính là O(g(n)) .
• Định nghĩa (Lower Bound). Cho bài toán P, ta nói cận dưới
cho thời gian tính của P là (g(n)) nếu mọi thuật toán giải P
đều có thời gian tính là (g(n)) .

• Định nghĩa. Cho bài toán P, ta nói thời gian tính của P là
(g(n)) nếu P có cận trên là O(g(n)) và cận dưới là (g(n)) .

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Một số lớp thuật toán

• Một số lớp thuật toán đặc biệt:


– O(1): hằng số (constant)
– O(log n): logarithmic
– O(n): tuyến tính (linear)
– O(n log n): trên tuyến tính (superlinear)
– O(n2): bình phương (quadratic)
– O(n3): bậc ba (cubic)
– O(an): hàm mũ (exponential ) (a > 1)
– O(nk): đa thức (polynomial) (k ≥ 1)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
NỘI DUNG

1.1. Ví dụ mở đầu

1.2. Thuật toán và độ phức tạp

1.3. Ký hiệu tiệm cận

1.4. Giả ngôn ngữ

1.5. Một số kĩ thuật phân tích thuật toán

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Mô tả thuật toán: giả ngôn ngữ

• Để mô tả thuật toán có thể sử dụng một ngôn ngữ lập trình nào
đó. Tuy nhiên điều đó có thể làm cho việc mô tả thuật toán trở
nên phức tạp đồng thời rất khó nắm bắt.
• Vì thế, để mô tả thuật toán người ta thường sử dụng giả ngôn
ngữ (pseudo language), trong đó cho phép vừa mô tả thuật
toán bằng ngôn ngữ đời thường vừa sử dụng những cấu trúc
lệnh tương tự như của ngôn ngữ lập trình.
• Dưới đây ta liệt kê một số câu lệnh chính được sử dụng trong
giáo trình để mô tả thuật toán.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Mô tả thuật toán: phỏng ngôn ngữ

• Khai báo biến


integer x,y;
real u, v;
boolean a, b;
char c, d;
datatype x;
• Câu lệnh gán
x = expression;
hoặc
x ← expression;
Ví dụ: x ← 1+4; y=a*y+2;

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Mô tả thuật toán: giả ngôn ngữ

• Cấu trúc điều khiển


if condition then
dãy câu lệnh
else
dãy câu lệnh
endif;

while condition do
dãy câu lệnh
endwhile;

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Mô tả thuật toán: phỏng ngôn ngữ

repeat
Câu lệnh case:
dãy câu lệnh;
until condition; Case
cond1: stat1;
for i=n1 to n2 [step d] cond2: stat2;
dãy câu lệnh; .
.
endfor; .
condn: stat n;
• Vào-Ra endcase;
read(X); /* X là biến đơn hoặc mảng */
print(data) hoặc print(thông báo)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Mô tả thuật toán: giả ngôn ngữ

• Hàm và thủ tục (Function and procedure)


Function name(các tham số)
begin
mô tả biến; Truyền tham số:
các câu lệnh trong thân của hàm;
• Tham trị
return (giá trị)
end; • Tham biến
• Biến cục bộ
Procedure name(các tham số)
begin • Biến toàn cục
mô tả biến;
các câu lệnh trong thân của hàm;
end;
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Mô tả thuật toán: phỏng ngôn ngữ

• Ví dụ: Thuật toán tìm phần tử lớn nhất trong mảng A(1:n)
Function max(A(1:n))
begin
datatype x; /* để giữ giá trị lớn nhất tìm được */
integer i;
x=A[1];
for i=2 to n do
if x < A[i] then
x=A[i];
endif
endfor ;
return (x);
end max;
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Mô tả thuật toán: giả ngôn ngữ

• Ví dụ: Thuật toán hoán đổi nội dung hai biến

Procedure swap(x, y)
begin
temp=x;
x = y;
y = temp;
end swap;

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
NỘI DUNG

1.1. Ví dụ mở đầu

1.2. Thuật toán và độ phức tạp

1.3. Ký hiệu tiệm cận

1.4. Giả ngôn ngữ

1.5. Một số kĩ thuật phân tích thuật toán

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Các kỹ thuật cơ bản
phân tích độ phức tạp của thuật toán

• Cấu trúc tuần tự. Gi¶ sö P vµ Q lµ hai ®o¹n cña thuËt to¸n, cã
thÓ lµ mét c©u lÖnh nh­ng còng cã thÓ lµ mét thuËt to¸n con.
Gäi Time(P), Time(Q) lµ thêi gian tÝnh cña P vµ Q t­¬ng øng.
Khi ®ã ta cã
Quy t¾c tuÇn tù: Thêi gian tÝnh ®ßi hái bëi “P; Q”, nghÜa lµ P
thùc hiÖn tr­íc, tiÕp ®Õn lµ Q, sÏ lµ
Time(P; Q) = Time(P) + Time(Q) ,
hoÆc trong ký hiÖu Theta:
Time(P; Q) = (max(Time(P), Time(Q)).

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Vòng lặp for

for i =1 to m do P(i);

• Giả sử thời gian thực hiện P(i) là t(i)


• Khi đó thời gian thực hiện vòng lặp for sẽ là
m

 t(i)
i 1

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ: Tính số Fibonaci
• Nếu coi các phép toán số học đòi hỏi thời
function Fibiter(n) gian là hằng số c, và không tính đến chi phí
begin tổ chức vòng lặp for thì thời gian tính của
i=0; j=1; hàm trên là (n).
• Do (công thức Muavre)
for k=2 to n do k k
begin 1   1  5   1  5  
fk     
5  2   2  
   
j= j+i;  
i= j-i; suy ra số bit biểu diễn fk là (k). Do đó thời
end; gian tính của một lần lặp là (k). Vậy thời
gian tính của Fibiter là:
Fibiter= j;
n n
end; n(n  1)
 ( n 2 )
 c.k  c k  c
k 1 k 1 2

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Phân tích vòng lặp While và Repeat

• Cần xác định một hàm của các biến trong vòng lặp sao
cho hàm này có giá trị giảm dần trong quá trình lặp. Khi
đó
– Để chứng minh tính kết thúc của vòng lặp ta chỉ cần chỉ ra
giá trị của hàm là số nguyên dương.
– Còn để xác định số lần lặp ta cần phải khảo sát xem giá trị
của hàm giảm như thế nào.
• Việc phân tích vòng lặp Repeat được tiến hành tương tự
như phân tích vòng lặp While.

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ: Tìm kiếm nhị phân (Binary Search)

Input: Mảng T[1..n] và số x


Giả thiết là x có
Output: Giá trị i: 1  i  n sao cho T[i] = x.
mặt trong mảng T
function Binary-Search(T[1..n], x);
begin
i:=1; j:=n;
while i < j do
k:= (i+j) div 2;
case
x < T[k]: j:=k-1;
x = T[k]: i:=k; j:=k; Binary-Search=k; exit; {Found!}
x > T[k]: i:=k+1;
end case
endwhile
end;

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Phân tích Binary-Search

• Gọi d= j-i+1. d – số phần tử của mảng cần tiếp tục khảo sát
• Ký hiệu i, j, i*, j* theo thứ tự là giá trị của i, j trước và sau khi
thực hiện lần lặp. Khi đó
– Nếu x < T[k], thì i*=i, j*=(i+j) div 2 - 1, vì thế d*=j*- i*+1
= (i+j) div 2 - 1- i + 1  (i+j)/2 - i < (j - i + 1)/2 = d/2.
– Nếu x > T[k], thì j*=j, i*=(i+j) div 2 + 1, vì thế d*=j*-
i*+1 = j - (i+j) div 2  j -(i+j-1)/2 - i = (j - i + 1)/2 = d/2.
– Nếu x = T[k], thì d* = 1 còn d  2

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Binary-Search (tiếp)

• Vậy luôn có: d*  d/2


• Do vòng lặp kết thúc khi d  1, nên từ đó suy ra thuật toán
phải kết thúc.
• Gọi dp là giá trị của j - i + 1 ở lần lặp thứ p  1 và d0 = n. Khi
đó
dp  dp-1/2, p  1.
• Thuật toán kết thúc tại bước p nếu dp  1, điều đó xảy ra khi p
= log n.
• Vậy thời gian tính của thuật toán là O(log n)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Các mô tả khác của thuật toán Binary Search

Function mid=bsearch1(L,p,q,key) Function mid=bsearch2(L,p,q,key)

while q>p while q>p


mid=floor((p+q)/2); mid=floor((p+q)/2);
if key<=L(mid) if key==L(mid)
q=mid; break break
p=mid;
else
p=mid+1; elseif key<L(mid)
end q=mid-1;
end else
p=mid+1;
if key==L(p) end
mid=p; end
else % Chú ý: p có thể có giá trị sai ở đây
mid=0; if key==L(p)
end mid=p;
else Hãy thử với:
mid=0;
Tìm thấy rồi thì dừng?! end
L = 1 , 2, 3
key = 1, 2, 3
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Hàm trên C

boolean binary_search_1(int* a, int n, int x) {


/* Test xem x có mặt trong mảng a[] kích thước n. */
int i;
while (n > 0) {
i = n / 2;
if (a[i] == x)
return true;
if (a[i] < x) { /* Tiếp tục tìm ở nửa trái */
a = &a[i + 1];
n = n - i - 1; }
else /* Tiếp tục tìm ở nửa phải */
n = i;
}
return false;
}
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Câu lệnh đặc trưng

• Định nghĩa. Câu lệnh đặc trưng là câu lệnh được


thực hiện thường xuyên ít nhất là cũng như bất kỳ câu
lệnh nào trong thuật toán.
• Nếu giả thiết thời gian thực hiện mỗi câu lệnh là bị
chặn bởi hằng số thì thời gian tính của thuật toán sẽ
cùng cỡ với số lần thực hiện câu lệnh đặc trưng
• => Để đánh giá thời gian tính có thể đếm số lần thực
hiện câu lệnh đặc trưng

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ: FibIter

function Fibiter(n)
begin
i:=0; j:=1; Câu lệnh đặc
for k:=1 to n do trưng
begin • Số lần thực hiện câu lệnh
j:= j+i; đặc trưng là n.
i:= j-i;
• Vậy thời gian tính của thuật
end;
toán là O(n)
Fibiter:= j;
end;

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ: Thuật toán 1 ví dụ mở đầu

int maxSum =0;


for (int i=0; i<n; i++) {
for (int j=i; j<n; j++) {
int sum = 0;
for (int k=i; k<=j; k++)
sum += a[k];
if sum > maxSum
maxSum = sum;
}
}
Chọn câu lệnh đặc trưng là sum+=a[k].
=> Đánh giá thời gian tính của thuật toán là O(n3)

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Ví dụ: Sắp xếp

• Nhận xét: Khi thuật toán đòi hỏi thực hiện nhiều vòng lặp lồng nhau, thì có
thể lấy câu lệnh nằm trong vòng lặp trong cùng làm câu lệnh đặc trưng.

• Tuy vậy, cũng cần hết sức thận trọng khi sử dụng cách lựa chọn này.
• Ví dụ. Sắp xếp kiểu nhốt chim vào chuồng (Pigeonhole Sorting).
Sắp xếp n số nguyên dương có giá trị nằm trong khoảng 1..s.
Đầu vào: T[1..n]: mảng chứa dãy cần sắp xếp.
Đầu ra: T[1..n]: mảng chứa dãy được sắp xếp không giảm.
Thuật toán bao gồm 2 thao tác:
– Đếm chim: Xây dựng mảng U[1..s], trong đó phần tử U[k] đếm số
lượng số có giá trị là k trong mảng T.
– Nhốt chim: Lần lượt nhốt U[1] con chim loại 1 vào U[1] lồng đầu tiên,
U[2] con chim loại 2 vào U[2] lồng tiếp theo, ...

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Sắp xếp kiểu nhốt chim

procedure Pigeonhole-Sorting;
begin
(* đếm chim *)
for i:=1 to n do inc(U[T[i]]);
(* Nhốt chim *)
i:=0;
for k:=1 to s do
while U[k]<>0 do
begin
i:=i+1;
T[i]:=k;
U[k]:=U[k]-1;
end;
end;

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Sắp xếp kiểu nhốt chim

• Nếu chọn câu lệnh bất kỳ trong vòng lặp while làm câu lệnh
đặc trưng, thì rõ ràng với mỗi k, câu lệnh này phải thực hiện
U[k] lần. Do đó số lần thực hiện câu lệnh đặc trưng là
s

 U [k ]  n
k 1

(do có tất cả n số cần sắp xếp). Từ đó ta có thời gian tính là


(n).

• Ví dụ sau đây cho thấy đánh giá đó chưa chính xác.


Giả sử T[i] = i2, i = 1, ..., n. Ta có

Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Sắp xếp kiểu nhốt chim

1, nÕu k lµ sè chÝnh ph­¬ng


U [k ]  
0, nÕu tr¸i l¹i,

Khi đó s = n2. Rõ ràng thời gian tính của thuật toán không phải
là O(n), mà phải là O(n2).
• Lỗi ở đây là do ta xác định câu lệnh đặc trưng chưa đúng, các
câu lệnh trong thân vòng lặp while không thể dùng làm câu lệnh
đặc trưng trong trường hợp này, do có rất nhiều vòng lặp rỗng
(khi U[k] = 0).
• Nếu ta chọn câu lệnh kiểm tra U[k] <> 0 làm câu lệnh đặc
trưng thì rõ ràng số lần thực hiện nó sẽ là n + s. Vậy thuật toán
có thời gian tính O(n+s) = O(n2).
Tham khảo tài liệu của PGS. TS. Nguyễn Đức Nghĩa
Chương 2: Thuật toán đệ quy

Trịnh Anh Phúc, Nguyễn Đức Nghĩa 1

1 Bộ môn Khoa Học Máy Tính, Viện CNTT & TT,


Trường Đại Học Bách Khoa Hà Nội.

Ngày 9 tháng 7 năm 2021

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 1 / 38
Giới thiệu

1 Khái niệm đệ quy


Hàm đệ qui
Tập hợp được xác định đệ qui

2 Thuật toán đệ qui

3 Một số ví dụ minh họa

4 Phân tích thuật toán đệ qui

5 Chứng minh tính đúng đắn của thuật toán đệ qui

6 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 2 / 38
Khái niệm đệ quy

Thuật toán đệ qui

Khái niệm đệ qui


Trong thực tế chúng ta thường gặp những đối tượng đệ quy bao gồm
chính nó hoặc được định nghĩa bởi chính nó. Ta nói các đối tượng đó được
xác định một cách đệ qui
Điểm quân số
Các hàm được định nghĩa đệ qui
Tập hợp được định nghĩa đệ qui
Định nghĩa đệ qui về cây
Fractal ....

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 3 / 38
Khái niệm đệ quy Hàm đệ qui

Hàm đệ qui (resursive functions)

Định nghĩa
Các hàm đệ qui được xác định bởi số nguyên không âm n theo sơ đồ
Bước cơ sở (Basic step) : Xác định giá trị hàm tại thời điểm n = 0
hay f (0)
Bước đệ qui (Recursive step) : Cho giá trị của hàm f (k) tại k ≤ n
đưa ra qui tắc tính giá trị của f (n + 1).

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 4 / 38
Khái niệm đệ quy Hàm đệ qui

Hàm đệ qui (resursive functions)


VD1 :
f (0) = 3 n = 0
f (n + 1) = 2f (n) + 3 n > 0
VD2 :
f (0) = 1
f (n + 1) = f (n) × (n + 1)

Pn
VD3 : Định nghĩa đệ qui tổng sn = i=1 ai

s 1 = a1
sn = sn−1 + an

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 5 / 38
Khái niệm đệ quy Tập hợp được xác định đệ qui

Tập hợp được xác định đệ qui

Định nghĩa
Tập hợp cũng có thể được xác định đệ qui theo sơ đồ tương tự như hàm
đệ qui
Bước cơ sở : Định nghĩa tập cơ sở.
Bước đệ qui : Xác định các qui tắc để sản sinh tập mới từ các tập
đã có.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 6 / 38
Khái niệm đệ quy Tập hợp được xác định đệ qui

Tập hợp được xác định đệ qui (tiếp)

VD1 : Xét tập S đc định nghĩa đệ qui như sau


Bước cơ sở : 3 là phần tử của tập S.
Bước đệ qui : Nếu x thuộc S và y thuộc S thì x + y thuộc S.
Vậy tập S có phân tử đc tạo một cách đệ qui 3, 3+3 = 6, 3+6 = 9,
6+6 = 12, · · ·
P
VD2 : Định nghĩa Pđệ qui của xâu như sau : = Bảng chữ cái
(alphabet) thì tập ∗ các xâu (string) trên bảng chữ cái A đc định
nghĩa đệ qui như sau :
P∗
Bước cơ sở : Xâu rỗng các phần
P∗ tử của P∗
Bước đệ qui : Nếu w thuộc và x thuộc A → wx thuộc .
P
Chẳng hạn tập các xâu nhị phân B thu được khi = {0, 1} bắt đầu
từ xâu rỗng, 0 , 1, 00, 01, 10, 11

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 7 / 38
Thuật toán đệ qui

1 Khái niệm đệ quy


Hàm đệ qui
Tập hợp được xác định đệ qui

2 Thuật toán đệ qui

3 Một số ví dụ minh họa

4 Phân tích thuật toán đệ qui

5 Chứng minh tính đúng đắn của thuật toán đệ qui

6 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 8 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Thuật toán đệ qui


Định nghĩa : Thuật toán đệ qui là thuật toán tự gọi đến chính mình với
đầu vào kích thước nhỏ hơn.
Tất nhiên việc sử dụng thủ tục đệ qui thích hợp với xử lý dữ liệu, tập
hợp, hàm, cây được định nghĩa cũng một cách đệ qui như các ví dụ
vừa nêu.
Các thuật toán được phát triển dựa trên phương pháp chia-để-trị
(Divide and Conquer) thông thường được mô tả dưới dạng đệ qui.
Hầu hết các ngôn ngữ lập trình đều cho phép gọi đệ qui của hàm -
lệnh gọi đến chính nó trong thân chương trình.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà 9Nội.
tháng
) 7 năm 2021 9 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Cấu trúc của thuật toán đệ qui


Function RecAlg(input)
begin
if (kích thước đầu vào là nhỏ nhất) then
thực hiện bước cơ sở /* giải bài toán với kích thước cơ sở*/
else
RegAlg(input với đầu vào nhỏ hơn);/* các bước đệ qui*/
Tổ hợp lời giải của các bài toán con để thu được lời-giải;
return(lời-giải)
endif
end;

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 10 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Phương pháp chia-để-trị


Phương pháp chia-để-trị (divide et impera) là một trong những phương
pháp chính dùng để thiết kế thuật toán có tính đệ qui, nó bao gồm 3 thao
tác chính như sau
Chia (Divide) bài toán cần giải thành các bài toán con
Bài toán con có kích thước nhỏ hơn và có cũng dạng với bài toán cần
giải.
Trị (Conquer) các bài toán con
Giải các bài toán con một cách đệ qui
Bài toán con có kích thước đủ nhỏ sẽ được giải thực tiếp
Tổ hợp (Combine) lời giải của các bài toán con
Thu đc lời giải của bài toán xuất phát.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 11 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Phương pháp chia-để-trị đc trình bày trong thủ tục đệ qui sau đây
Procedure D-and-C(n)
if n ≤ n0 then
Giải bài toán một cách trực tiếp
else
Chia bài toán thành a bài toán con kích thước n/b;
for (mỗi bài toán trong a bài toán con) do D-and-C(n/b) endfor
Tổng hợp lời giải của a bài toán con để thu được lời giải của
bài toán gốc;
endif
End

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 12 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Phương pháp chia để trị đc trình bày trong thủ tục đệ qui (tiếp)
Các thông số quan trọng của thuật toán
n0 kích thước nhỏ nhất của bài toán con (còn gọi là neo đệ qui). Bài
toán con với kích thước n0 sẽ được giải trực tiếp.
a - số lượng bài toán con cần giải.
b - liên quan đến kích thước của bài toán con được chia.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 13 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Tìm kiếm nhị phân


Đầu vào : Cho mảng x[] và khóa tìm kiếm y
Đầu vào : Tìm thấy, chỉ số i sao cho x[i] == y
ngược lại, không tìm thấy trả lại -1

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 14 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Tìm kiếm nhị phân (tiếp)


Cho mảng số x = [1..n] được sắp xếp theo thứ tự không giảm và số y. Cần
tìm chỉ số (1 ≤ i ≤ n) sao cho x[i] = y.
Để đơn giản, ta giả thiết chỉ số i tồn tại. Thuật toán để giải bài toán dựa
trên lập luận sau : với số y cho trước
hoặc là bằng phần tử nằm giữa mảng x
hoặc là nằm nửa bên trái mảng x
hoặc là nằm nửa bên phải mảng x

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 15 / 38
Thuật toán đệ qui

Thuật toán đệ qui

Tìm kiếm nhị phân (tiếp)


Hàm C trả lại giá trị chỉ số i nếu tìm thấy y, không thì trả lại -1.
int Bsearch(int *x, int start, int finish,int y){
int middle;
middle = (start+finish)/2;
if(start==finish){/* Neo de qui */
if(y==x[middle]) return middle; else return -1; }
if(y==x[middle]) return middle;/* Tim thay */
else{
if(x[middle]<y) /* Tim y nam mang ben phai */
return Bsearch(x,middle+1,finish,y);
/* Tim y nam mang ben trai */
else return Bsearch(x,start,middle-1,y);
}
}
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 16 / 38
Một số ví dụ minh họa

1 Khái niệm đệ quy


Hàm đệ qui
Tập hợp được xác định đệ qui

2 Thuật toán đệ qui

3 Một số ví dụ minh họa

4 Phân tích thuật toán đệ qui

5 Chứng minh tính đúng đắn của thuật toán đệ qui

6 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 17 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 1 : Tính n!
Hàm f(n) = n! được định nghĩa đẹ qui như sau
Bước cơ sở : f(0) = 0! = 1
Bước đệ qui : f(n) = n f(n-1), với n>0
Hàm đệ qui viết bằng ngôn ngữ C
int Fact(int n){
if(n==0) return 1;
else return n*Fact(n-1);
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 18 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 2 : Tính số Fibonacci
Dãy số Fibonacci đc định nghĩa như sau :
Bước cơ sở : F(0) = 1, F(1) = 1;
Bước đệ qui : F(n) = F(n-1) + F(n-2) với n ≥ 2
Hàm đệ qui viết bằng ngôn ngữ C
int FibRec(int n){
if(n<=1) return 1;
else return FibRec(n-1) + FibRec(n-2);
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 19 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 3 : Tính hệ số nhị thức Cnk


Hệ số C (n, k) đc định nghĩa như sau :
Bước cơ sở : C (n, 0) = 1, C (n, n) = 1 ∀n ≥ 0;
Bước đệ qui : C (n, k) = C (n − 1, k − 1) + C (n − 1, k) 0 < k < n
Hàm đệ qui viết bằng ngôn ngữ C
int C(int n,int k){
if((k==0) || (k==n)) return 1;
else return C(n-1,k-1) + C(n-1,k);
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 20 / 38
Một số ví dụ minh họa

Thuật toán đệ qui


Ví dụ 4 : Bài toán tháp Hà Nội
Trò chơi tháp Hà Nội được trình bày như sau : Có 3 cọc A, B, C. Trên cọc
A có một chồng gồm n cái đĩa đường kính giảm dần (xem hình vẽ). Cần
phải chuyển chồng đĩa từ cọc A sang cọc C tuân theo qui tắc, mỗi lần
chuyển một đĩa và chỉ được xếp đĩa có đường kính nhỏ lên trên đĩa có
đường kính lớn hơn đồng thời được dùng cọc B làm cọc trung gian.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 21 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 4 : Bài toán tháp Hà Nội (tiếp)


Bài toán đặt ra là tìm cách chơi đòi hỏi số lần di chuyển đĩa ít nhất. Các
lập luận sau đây được sử dụng để xây dựng thuật toán giải quyết bài toán
đặt ra
Nếu n = 1 thì ta chỉ việc chuyển đĩa cọc A sang cọc C
Trong trường hợp n ≥ 2 việc di chuyển đĩa gồm các bước đệ qui như
sau
1 chuyển n − 1 đĩa từ cọc A đến cọc B sử dụng cọc C làm trung gian.
Bước này cũng phải thực hiện với số lần di chuyển nhỏ nhất, nghĩa là
ta phải giải bài toán tháp Hà Nội với n − 1 đĩa.
2 chuyển 1 đĩa đường kính lớn nhất từ cọc A đến cọc C.
3 chuyển n − 1 đĩa từ cọc B đến cọc C - sử dụng cọc A làm trung gian.
Bước này cũng phải thực hiện với số lần di chuyển nhỏ nhất, nghĩa là
ta lại phải giải bài toán tháp Hà Nội với n − 1 đĩa.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 22 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 4 : Bài toán tháp Hà Nội (tiếp)


Trong trường hợp n ≥ 2, hai bước nhỏ 1 và 3 cần số lần di chuyển ít nhất
khi thực hiện hai bước này là 2 × hn−1 , do đó nếu gọi số lần di chuyển đĩa
ít nhất là hn , ta có công thức đệ qui sau

h1 = 1,
h2 = 2h1 + 1, ...
hn = 2hn−1 + 1, n ≥ 2

sử dụng phương pháp thế từng bước, ta có

hn = 2 n − 1

như vậy độ phức tạp của thuật toán là hàm số mũ

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 23 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 4 : Bài toán tháp Hà Nội (tiếp)


Mã giả của thuật toán đệ qui giải bài toán tháp Hà Nội như sau
Procedure HanoiTower(n,a,b,c)
if (n=1) then
<chuyển đĩa từ cọc A sang cọc C>
else
HanoiTower(n-1,A,C,B)
HanoiTower(1,A,B,C)
HanoiTower(n-1,B,A,C)
endif
End

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 24 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 4 : Bài toán tháp Hà Nội (tiếp)


Mã nguồn C của thuật toán đệ qui giải bài toán tháp Hà Nội như sau
# include <stdio.h>
# include <conio.h>
int i=0;
int main(){
int disk;
printf(" Nhập số đĩa : ");
scanf("%d",&disk);
move(disk,’A’,’C’,’B’);
printf(" Tổng số lần di chuyển %d",i);
getch();
return 0;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 25 / 38
Một số ví dụ minh họa

Thuật toán đệ qui

Ví dụ 5 : Bài toán tháp Hà Nội (tiếp)


Mã nguồn C của thuật toán đệ qui giải bài toán tháp Hà Nội như sau
void move(int n, char start, char finish, char spare){
if(n==1){
printf("chuyen dia tu coc %c sang coc %c ",start,finish);
i++;
return;
}else{
move(n-1,start,spare,finish);
move(1,start,finish,spare);
move(n-1,spare,finish,start);
}
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 26 / 38
Phân tích thuật toán đệ qui

1 Khái niệm đệ quy


Hàm đệ qui
Tập hợp được xác định đệ qui

2 Thuật toán đệ qui

3 Một số ví dụ minh họa

4 Phân tích thuật toán đệ qui

5 Chứng minh tính đúng đắn của thuật toán đệ qui

6 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 27 / 38
Phân tích thuật toán đệ qui

Phân tích thuật toán đệ qui

Các bước tiến hành phân tích thuật toán đệ qui


Gọi T(n) là thời gian tính của thuật toán
Xây dựng công thức đệ qui cho T(n)
Giải công thức đệ qui thu được để đưa ra đánh giá cho T(n)
Vì ta chỉ cần một đánh giá sát cho tốc độ của T(n) nên việc giải công
thức đệ qui đối với T(n) được hiểu là việc đưa ra đánh giá tốc độ tăng của
T(n) trong ký hiệu tiệm cận.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 28 / 38
Phân tích thuật toán đệ qui

Phân tích thuật toán đệ qui (tiếp)

Ví dụ 1 : Thuật toán FibRec


int FibRec(int n){
if(n<=1) return n;
else return FibRec(n-1) + FibRec(n-2);
}
Gọi T(n) là số phép toán cộng phải thực hiện trong lệnh gọi FibRec(n), ta

T(0) = 0, T(1) = 0
T(n) = T(n-1) + T(n-2) + 1, n>1
Chú ý : Phép toán cộng trong trường hợp (n>1), bằng qui nạp ta có :
T(n) = Θ(Fn ), tương đương thời gian tính tăng tốc độ cỡ (1.6181)n

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 29 / 38
Phân tích thuật toán đệ qui

Phân tích thuật toán đệ qui (tiếp)

Thủ tục chia để trị


Procedure D-and-C(n)
begin
if n ≤ n0 then
Giải bài toán một cách trực tiếp
else
Chia bài toán thành a bài toán con kích thước n/b;
for (mỗi bài toán trong a bài toán con) do D-and-C(n/b);
Tổ hợp lời giải của a bài toán con để thu được lời giải của bài
toán gốc;
endif
end

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 30 / 38
Phân tích thuật toán đệ qui

Phân tích thuật toán đệ qui (tiếp)

Thủ tục chia để trị (tiếp)


Gọi T(n) là thời gian giải bài toán kích thước n. Thời gian của giải thuật
chia-để-trị đc đánh giá thời gian thực hiện 3 thao tác của thuật toán
Chia bài toán thành a bài toán con, mỗi bài toán kích thước n/b, đòi
hỏi thời gian D(n)
Trị các bài toán con : a T(n/b)
Tổ hợp các lời giải : C (n)
Vậy ta có công thức đệ qui sau đây để tính T(n) :
(
Θ(1), n ≤ n0
T (n) =
aT (n/b) + D(n) + C (n), n > n0

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 31 / 38
Phân tích thuật toán đệ qui

Phân tích thuật toán đệ qui (tiếp)

Định lý thợ - Master theorem


Giả sử a ≥ 1 và b > 1, c ≥ 0 là các hằng số. Xét T(n) là công thức đệ qui

T (n) = aT (n/b) + cnk

xác định với n ≥ 0 có ba tình huống


1 nếu a > b k thì T (n) = Θ(nlogb a )
2 nếu a = b k thì T (n) = Θ(nk log n)
3 nếu a < b k thì T (n) = Θ(nk )

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 32 / 38
Phân tích thuật toán đệ qui

Phân tích thuật toán đệ qui (tiếp)

Ví dụ 2 : Giải thuật tìm kiếm nhị phân


Gọi T (n) thời gian chạy của giải thuật tìm kiếm nhị phân
Bước cơ sở T (1) = c
Bước đệ quy T (n) = T (n/2) + c
trong đó
a=1
b=2
k=0
ta áp dụng tình huống 2 nên T (n) = Θ(log n)

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 33 / 38
Chứng minh tính đúng đắn của thuật toán đệ qui

1 Khái niệm đệ quy


Hàm đệ qui
Tập hợp được xác định đệ qui

2 Thuật toán đệ qui

3 Một số ví dụ minh họa

4 Phân tích thuật toán đệ qui

5 Chứng minh tính đúng đắn của thuật toán đệ qui

6 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 34 / 38
Chứng minh tính đúng đắn của thuật toán đệ qui

Thuật toán đệ qui

Định nghĩa đệ qui và qui nap toán học


Định nghĩa đệ qui và qui nạp toán học có những nét tương đồng và bổ
sung cho nhau. Chứng minh bằng qui nạp toán học thường dùng làm cơ
sở để xây dựng giải thuật đệ qui để giải quyết bài toán. Chứng minh bằng
qui nạp thường gồm hai phấn
Bước cơ sở qui nạp : tương đương bước cơ sở trong định nghĩa đệ
qui
Bước chuyển qui nạp : tương đương bước đệ qui trong định nghĩa
đệ qui

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 35 / 38
Chứng minh tính đúng đắn của thuật toán đệ qui

Chứng minh tính đúng đắn của thuật toán đệ qui

Vậy để chừng minh tính đúng đắn của thuật toán đệ qui thông thường ta
sử dụng qui nạp toán học. Ngược lại, cách chứng minh bằng đệ qui cũng
thường là cơ sở để xây dựng nhiều thuật toán đệ qui.
VD1 Chứng minh Fact(n) = n! vậy ta sẽ chứng minh bằng qui nạp
toán học
Bước cơ sở qui nạp : Ta có Fact(0) = 1 = 0!
Bước chuyển qui nạp : Giả sử Fact(n-1) cho giá trị của (n-1)! ta phải
chứng minh Fact(n) cho giá trị n!. Thật vậy, do giá trị trả lại của
Fact(n)

n ∗ Fact(n − 1) ⇒
|{z} n ∗ (n − 1)! = n!
theo giả thiết qui nạp

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 36 / 38
Chứng minh tính đúng đắn của thuật toán đệ qui

Chứng minh tính đúng đắn của thuật toán đệ qui (tiếp)

VD2 : Cho mặt phẳng trên đó vẽ n đường thẳng. Chứng minh mệnh
đề sau bằng qui nạp : P(n) luôn có thể tô các phần được chia bởi n
đường thẳng bởi chỉ hai mầu : xanh và đỏ (Xem chứng minh trong
sách).
Mã giả giải thuật tô hai mầu mặt phẳng như sau
Procedure PaintColor(n,A,B)
<xét đường thẳng n>
<phân chia các phần mặt phẳng thành hai tập A,B>
if (n=1) then
A ← Xanh; B ← Đỏ;
else
PaintColor(n-1,A,B)
<đảo mầu các phần mặt phẳng thuộc A>
endif
End
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 37 / 38
Tổng kết

Tổng kết

Khái niệm về đệ quy và thuật toán đệ quy


Phân tích thời gian chạy của thuật toán đệ quy
Chứng minh tính đúng đắn của thuật toán đệ quy bằng quy nạp

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà9 Nội.
tháng) 7 năm 2021 38 / 38
Chương 3 : Các cấu trúc dữ liệu cơ bản

Trịnh Anh Phúc 1

1 Bộ môn Khoa Học Máy Tính, Viện CNTT & TT,


Trường Đại Học Bách Khoa Hà Nội.

Ngày 13 tháng 7 năm 2021

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 1 / 71
Giới thiệu
1 Các khái niệm
Kiểu dữ liệu trừu tượng
Cấu trúc dữ liệu
Con trỏ
2 Mảng
3 Danh sách
Định nghĩa
Các cách cài đặt danh sách tuyến tính
4 Ngăn xếp
Định nghĩa
Các cách cài đặt ngăn xếp
Ứng dụng
5 Hàng đợi
Định nghĩa
Các cách cài đặt hàng đợi
Ứng dụng
6 Tổng kết
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 2 / 71
Các khái niệm
Kiểu dữ liệu
Các kiểu dữ liệu được đặc trưng bởi
Tập các giá trị
Cách biểu diễn dữ liệu được sử dụng chung cho tất cả các giá trị
Tập các phép toán có thể thực hiện trên tất cả các giá trị này.

Ví dụ các kiểu dữ liệu trong C


Kiểu Bits Giá trị nhỏ nhất Giá trị lớn nhất
char 8 -128 127
short 16 -32768 32767
unsigned int 16 0 65535
long 32 −231 231 − 1
float 32 −3.4 × 1038 3.4 × 1038
double 64 −1.7 × 10308 1.7 × 10308
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 3 / 71
Các khái niệm
Kiểu dữ liệu trừu tượng
Kiểu dữ liệu trừu tượng bao gồm :
Tập các giá trị
Tập các phép toán có thể thực hiện trên tất cả các giá trị này.

Rõ ràng không có cách biểu diễn dữ liệu chung cho dữ liệu trừu tượng

Kiểu Đối tượng Phép toán


Mảng các phần tử khởi tạo (create), chèn (insert), ...
Danh sách các phần tử chèn (insert), xóa (delete), tìm (search), ...
Đồ thị đỉnh, cạnh duyệt (traverse), tìm đường (search path), ...
Ngăn xếp các phần tử gắp (pop), ấn (push), kiểm tra rỗng, ...
Hàng đợi các phần tử vào hàng (enqueue), ra khỏi hàng (dequeue),
Cây gốc, lá, cành duyệt (traverse), tìm kiếm (search), ...
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 4 / 71
Các khái niệm

Cấu trúc dữ liệu


Định nghĩa : Cấu trúc dữ liệu là một họ các biến, có thể có kiểu dữ liệu
khác nhau, được liên kết lại theo một cách thức nào đó.
Ô (cell) là đơn vị cơ sở cấu thành cấu trúc dữ liệu. Có thể hình dung
ô như cái hộp đựng giá trị phát sinh từ một kiểu dữ liệu cơ bản hay
phức hợp.
Cấu trúc dữ liệu đc tạo nhờ đặt tên cho một nhóm (group) các ô và
đặt giá trị cho một số ô để mô tả sự liên kết giữa các ô.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 5 / 71
Các khái niệm

Cấu trúc dữ liệu (tiếp)


Có ba phương pháp tạo nhóm
Dùng mảng là một dãy các ô có cùng kiểu dữ liệu xác định
e.g. int name[100]
Dùng cấu trúc bản ghi là ô được tạo bởi một họ các ô (gọi là các
trường) có thể có kiều rất khác nhau.
struct record{
float data;
int next;} reclist[100];
Dùng file là giống mảng tuy nhiên các phần tử của nó chỉ truy cập
được một cách tuần tự.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 6 / 71
Các khái niệm

Con trỏ (pointer)


Định nghĩa : Con trỏ (pointer) là ô mà giá trị của nó chỉ sang một ô khác.

A B

Khi vẽ cấu trúc dữ liệu sử dụng con trỏ, để thể hiện ô A trỏ sang ô B, ta
sẽ sử dụng mũi tên hướng từ A đến B.
Ví dụ : Để khai báo con trỏ ptr trong C trỏ đến ô có kiêu dữ liệu cho
trước tên là celltype
celltype *ptr

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 7 / 71
1 Các khái niệm
Kiểu dữ liệu trừu tượng
Cấu trúc dữ liệu
Con trỏ
2 Mảng
3 Danh sách
Định nghĩa
Các cách cài đặt danh sách tuyến tính
4 Ngăn xếp
Định nghĩa
Các cách cài đặt ngăn xếp
Ứng dụng
5 Hàng đợi
Định nghĩa
Các cách cài đặt hàng đợi
Ứng dụng
6 Tổng kết
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 8 / 71
Mảng

Mảng
Mảng là dữ liệu trừu tượng
Tập các giá trị : tập các cặp < index, value > trong đó với mỗi giá trị
của index có một giá trị từ tập các giá trị.
Các thao tác cơ bản :
I Khởi tạo
I Chèn phần tử
I Xóa bỏ một phần tử

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 9 / 71
Mảng

Phân bổ bộ nhớ cho mảng


Thông thường mảng được chiếm giữ một dãy liên tiếp các từ máy trong
bộ nhớ, cần lưu ý khái niệm từ máy trong mỗi ngôn ngữ lập trình là khác
nhau và kích thước khác nhau nên tính toán việc phân bổ này không thể
đồng nhất cho mọi ngôn ngữ.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 10 / 71
Mảng

Ví dụ
# include <stdio.h>
# include <conio.h>
int main(){
int one[] = {0,1,2,3,4};
int *ptr; int rows = 5;
/* in địa chỉ của mảng một chiều dùng con trỏ */
int i; ptr = one;
for(i=0;i<rows;i++)
printf("%8u %5d",ptr+i,*(ptr+i));
}

Tuy vậy, khi dùng hai trình dịch DEVC và TC lại cho kết quả khác nhau vì
kích thước của dữ liệu int lần lượt là : 4, 2.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 11 / 71
Mảng

Các thao tác với mảng


Chèn một phần tử vào mảng : Do mảng có kích thước xác định nên
nếu ta muốn chèn một phần tử mới vào thì ta phải dịch các phần tử
phía sau ô được đánh dấu để đảm bảo trình tự của mảng
Xóa bỏ một phần tử : Ngược lại khi xóa bỏ một phần tử thì ta dồn
các phần tử còn lại sau chỗ đánh dấu lên.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 12 / 71
1 Các khái niệm
Kiểu dữ liệu trừu tượng
Cấu trúc dữ liệu
Con trỏ
2 Mảng
3 Danh sách
Định nghĩa
Các cách cài đặt danh sách tuyến tính
4 Ngăn xếp
Định nghĩa
Các cách cài đặt ngăn xếp
Ứng dụng
5 Hàng đợi
Định nghĩa
Các cách cài đặt hàng đợi
Ứng dụng
6 Tổng kết
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 13 / 71
Danh sách

Danh sách tuyến tính


Danh sách tuyến tính là một dãy gồm không hoặc nhiều hơn các phần tử
cùng kiểu cho trước : (a1 , a2 , · · · , an ) n ≥ 0
ai là một phần tử của danh sách.
a1 là phần tử đầu tiên còn an là phần tử cuối cùng.
n là độ dài của danh sách.
Khi n = 0 ta có danh sách rỗng, các phần tử được sắp xếp một cách tuyến
tính hay ai trước ai+1 và sau ai−1 .

Ví dụ :
Danh sách các sinh viên được sắp theo tên
Danh sách các cầu thủ có số áo tăng dần

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 14 / 71
Danh sách

Danh sách tuyến tính (tiếp)


Các thao tác cơ bản :
Khởi tạo
Chèn phần tử
Định vị trí của một phần tử
Truy xuất một phần tử
Xóa bỏ một phần tử
Trả lại vị trí sau ví trí p
Trả lại vị trí trước ví trí p
Trả lại vị trí đầu tiên
Tạo mảng rỗng
In ra danh sách các phần tử

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 15 / 71
Danh sách

Các cách cài đặt danh sách tuyến tính


Có ba cách cài đặt danh sách tuyến tính cơ bản sau
Dùng mảng (Array list)
I Cất giữ các phần tử của danh sách vào các ô liên tiếp của mảng.
Danh sách liên kết (Linked list)
I Các phần tử được cất giữ tại các chỗ khác nhau trong bộ nhớ.
I Mối phần tử có một con trỏ (pointer) trỏ đến phần tử tiếp theo.
Địa chỉ không trực tiếp (indirect addressing)
I Các phần tử của danh sách có thể đc cất giữ các chỗ tùy ý trong bộ
nhớ.
I Tạo bảng các địa chỉ trong đó phần tử thứ i sẽ cho biết địa chỉ lưu trữ
phần tử ai .

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 16 / 71
Danh sách
Cài đặt danh sách tuyến tính : dùng mảng
Ta cất giữ các phần tử của danh sách vào các ô liên tiếp của mảng. Vậy
danh sách là cấu trúc gồm hai thành phần
1 là mảng gồm các phần tử.
2 last - vị trí của phần tử cuối cùng trong danh sách.
Vị trí có kiểu nguyên và chạy trong khoảng từ 0 đến độ dài mảng -1.

Phần tử đầu tiên ← first


Phần tử thứ hai
..
.
...
Phần tử cuối cùng ← last
rỗng
rỗng
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 17 / 71
Danh sách dùng mảng

Định nghĩa cấu trúc dữ liệu danh sách dùng mảng


Mã nguồn ngôn ngữ C cài đặt danh sách dùng mảng
#define MAXLEN 100
typedef int element_type;
typedef struct LIST{
element_type elements[MAXLEN];
int last;
}list_type;

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 18 / 71
Danh sách dùng mảng
Thao tác chèn
Mã giả của thao tác chèn phần tử x vào danh sách L tại vị trí p
Procedure Insert(x, p, L)
1 if (L.last ≥ MAXLEN) then <Báo lỗi tràn danh sách> else
2 if (p>L.last + 1) or (p<1) then <Báo lỗi vị trí p không tồn tại>
3 else /* Đẩy các phần tử dưới p xuống 1 vị trí */
4 for q ← L.last downto p do
5 L.elements[q+1] ← L.elements[q]
6 endfor
7 L.last ← L.last + 1
8 L.elements[p] ← x
9 endif
10 endif
End
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 19 / 71
Danh sách dùng mảng

Xóa bỏ phần tử
Mã giả của thao tác loại phần tử tại vị trí p trong danh sách L
Procedure Delete(p,L)
1 if (p>L.last + 1) or (p<1) then <Báo lỗi vị trí p không tồn tại>
2 else
3 L.last ← L.last - 1
4 for q ← p to L.last do /* Đẩy các phần tử dưới p lên 1 vị trí */
5 L.elements[q] ← L.elements[q+1]
6 endfor
7 endif
End

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 20 / 71
Danh sách

Cài đặt danh sách tuyến tính : dùng danh sách móc nối (linked list)
Nhược điểm của việc sử dụng mảng là
Lưu trữ hay bổ sung một phần tử tốn kém thời gian.
Lãng phí khoảng bộ nhớ rỗng không dùng đến.
Phải duy trì một khoảng không gian lưu trữ liên tục trong bộ nhớ.
Để khắc phục nó ta có thể dùng danh sách móc nối sử dụng con trỏ
(pointer), ta xét cách tổ chức móc nối sau
Danh sách móc nối đơn (singly linked list)
Danh sách nối kép (doubly linked list)

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 21 / 71
Danh sách

Danh sách móc nối đơn


Danh sách gồm các ô (các nút), mỗi ô chứa một phần tử (element) của
danh sách và con trỏ (pointer) trỏ đến ô kế tiếp của danh sách.

element pointer

Có một ô đặc biệt gọi là ô header để trỏ ra ô chứa phần tử đều tiên trong
danh sách, ô này không chứa phần tử nào cả.

pointer

Ngược lại, ô cuối cùng trong danh sách lại có con trỏ trỏ vào giá trị NULL.

element NULL

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 22 / 71
Danh sách

Danh sách móc nối đơn (tiếp)


Nếu danh sách gồm các phần tử a1 , a2 , · · · , an thì danh sách móc nối
được tổ chức như trong hình vẽ

a1 a2 an null

Mối nối chỉ ra địa chỉ bộ nhớ của nút tiếp theo trong danh sách

Cài đặt danh sách móc nối đơn trong C


typedef <kiểu dữ liệu> ElementType;
struct _PointerType{
ElementType Inf;
struct _PointerType *Next;
};
typedef struct _PointerType PointerType;

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 23 / 71
Danh sách
Danh sách móc nối đơn : thao tác chèn
PointerType *InsertMiddle(PointerType *Prev, ElementType X){
PointerType *TempNode;
TempNode = (PointerType *)malloc(sizeof(PointerType));
TempNode->Inf = X;
TempNode->Next = Prev->Next;
Prev->Next = TempNode;
return TempNode;
}

Prev
... Inf Inf ... null

Inf
TempNode
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 24 / 71
Danh sách
Danh sách móc nối đơn : thao tác xóa
ElementType Delete(PointerType *Prev){
ElementType X;
PointerType *TempNode;
TempNode = Prev->Next; Prev->Next = Prev->Next->Next;
X = TempNode->Inf;
free(TempNode);
return X
}

Prev
... Inf Inf ... null

Inf
TempNode
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 25 / 71
Danh sách
Danh sách móc nối đơn : chèn một nút vào đầu danh sách
PointerType *InsertToHead(PointerType *First, ElementType X){
PointerType *TempNode;
TempNode = (PointerType *) malloc(sizeof(PointerType));
TempNode->Inf = X;
TempNode->Next = First;
First = TempNode;
return First;
}

First
Inf Inf ... null

Inf
TempNode
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 26 / 71
Danh sách
Danh sách móc nối đơn : chèn một nút vào cuối danh sách
PointerType *InsertToLast(PointerType *First, ElementType X){
PointerType *NewNode; PointerType *TempNode;
NewNode = (PointerType *)malloc(sizeof(PointerType));
NewNode->Inf = X; TempNode = First;
while(TempNode->Next!=NULL)
TempNode = TempNode->Next;
TempNode->Next = NewNode;
return First;
}

First TempNode
Inf ... Inf

NewNode
Inf null
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 27 / 71
Danh sách

Danh sách móc nối đơn : xóa nút đầu danh sách
PointerType *DeleteHead(PointerType *First){
PointerType *TempNode;
TempNode = First->Next;
free(First);
return TempNode;
}

First
Inf ... null

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 28 / 71
Danh sách
Danh sách móc nối đơn : xóa nút cuối danh sách
PointerType *DeleteLast(PointerType *First){
PointerType *Temp1,*Temp2;
Temp1 = First; Temp2 = First;
while(Temp1->Next != NULL){
Temp2 = Temp1;
Temp1 = Temp1->Next;}
Temp2->Next = NULL;
free(Temp1);
return First;
}

First Temp2 Temp1


... Inf Inf null

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 29 / 71
Danh sách

Danh sách móc nối đơn : kiểm tra danh sách rỗng
int IsEmpty(PointerType *First)
{
return !First;
}

Danh sách móc nối đơn : Xóa danh sách


PointerType *MakeNull(PointerType *First)
{
while(!IsEmpty(First))
First=DeleteHead(First);
return First;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 30 / 71
Danh sách

Danh sách móc nối đơn : in ra tất cả các phần tử trong danh sách
void Print(PointerType *First){
PointerType *TempNode;
TempNode = First; int count = 0;
while(TempNode){
printf("%6d",TempNode->Inf); count++;
TempNode = TempNode->Next;
}
printf("\n");
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 31 / 71
1 Các khái niệm
Kiểu dữ liệu trừu tượng
Cấu trúc dữ liệu
Con trỏ
2 Mảng
3 Danh sách
Định nghĩa
Các cách cài đặt danh sách tuyến tính
4 Ngăn xếp
Định nghĩa
Các cách cài đặt ngăn xếp
Ứng dụng
5 Hàng đợi
Định nghĩa
Các cách cài đặt hàng đợi
Ứng dụng
6 Tổng kết
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 32 / 71
Ngăn xếp
Kiểu dữ liệu trừu tượng ngăn xếp
Định nghĩa : là dạng đặc biệt của danh sách tuyến tính đã trình bầy trong
đó các phần tử được đẩy vào (push) và lấy ra (pop) chỉ từ một đầu, đc
gọi là đỉnh (top), của danh sách đó.
Nguyên tắc : Vào sau ra trước, First-In Last-Out (FILO)
Các thao tác với ngăn xếp
Đẩy vào (push) bổ sung một phần tử.
Lấy ra (pop) loại bỏ một phần tử.
Trả lại phần tử nạp sau cùng (top) mà không loại bỏ.
Trả lại số phần tử (size) trong ngăn xếp.
Nhận biết nó có rồng hay không (IsEmpty).
Có hai cách cài đặt
sử dụng mảng
sử dụng con trỏ
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 33 / 71
Ngăn xếp
Minh họa ngăn xếp với hai thao tác cơ bản : đẩy vào (push) và lấy ra
(pop) đều thực hiện từ từ một đầu (top) của ngăn xếp.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 34 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng mảng trong ngôn ngữ C


typedef ... Item;
static Item *s;
static int N;
void STACKinit(int maxN){
s = (Item *)malloc(maxN*sizeof(Item));
N=0;
}
int STACKempty(){ return N==0;}
void STACKpush(Item item){ s[N++] = item;}
item STACKpop(){return s[- -N];}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 35 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng con trỏ


Cũng như cách mô tả dang sách móc nối, chỉ khác là ngăn xếp được cài
đặt sao cho thao tác bổ sung và loại bỏ chỉ làm việc với ô đầu tiên
struct StackNode{
float item;
StackNode *next;
};
struct Stack{
StackNode *top;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 36 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng con trỏ (tiếp)


Các phép toán cơ bản
Khởi tạo
Kiểm tra ngăn xếp rỗng
Kiểm tra tràn ngăn xếp
Đẩy phần tư vào ngăn xếp
Lấy một phần tử ra
In ra các phần tử của ngăn xếp

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 37 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng con trỏ : Khởi tạo


Stack *StackInit(){
Stack *s;
s = (Stack *)malloc(sizeof(Stack));
if (s==NULL){
return NULL;
}
s->top = NULL;
return s;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 38 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng con trỏ : Hủy ngăn xếp
void StackDestroy(Stack *s){
while(!StackEmpty(s)){
StackPop(s);
}
free(s);
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 39 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng con trỏ : các hàm bổ trợ
int StackEmpty(const Stack *s){
return (s->top==NULL);
}

int StackFull(){
printf("\n Khong con bo nho");
getch();
return 1;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 40 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng con trỏ : đẩy phần tử vào ngăn xếp
int StackPush(Stack *s, float *item){
StackNode *node;
node = (StackNode *)malloc(sizeof(StackNode));
if(node==NULL){
StackFull();
return 1;
}
node->item = item;
node->next = s->top;
s->top = node;
return 0;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 41 / 71
Ngăn xếp

Cài đặt ngăn xếp sử dụng con trỏ : lấy phần tử từ ngăn xếp
float StackPop(Stack *s){
float item;
StackNode *node;
if(StackEmpty(s)){
printf("\n Ngan xep rong");
return NULL;
}
node = s->stop;
item = node->item;
s->top = node->next;
free(node);
return item;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 42 / 71
Ngăn xếp
Cài đặt ngăn xếp sử dụng con trỏ : in các phần tử ngăn xếp
int disp(Stack *s){
StackNode *node;
float m;
printf("\n DANH SACH CAC PHAN TU CUA NGAN XEP \n");
if(StackEmpty(s)){
printf("\n ngan xep rong \n");
getch();
}else{
node = s->top;
do{
m = node->item; printf("% 8.3f",m);
node = node->next;
}while(!(node==NULL));
}
}
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 43 / 71
Ngăn xếp

Ứng dụng 1 : Bài toán đổi cơ số


Cho một số trong số thập phân, ví dụ n = 2013 chuyển nó sang số có giá
trị tương đương trong hệ cơ số
b = 2 thì ta có số n(b) = 11111011101
b = 8 thì ta có số n(b) = 3735
b = 16 thì ta có số n(b) = 7DD
Việc đổi cơ số có được do sử dụng ngăn xếp để tạo nên giá trị tương
đương của n trong hệ cơ số mới b được trình bầy bởi giải thuật sau...

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 44 / 71
Ngăn xếp

Ứng dụng 1 : Bài toán đổi cơ số (tiếp)


Chuyển số bất kỳ trong hệ thập phân n thành số giá trị tương đương trong
hệ cơ số b, nghĩa là n(b) .
Giải thuật dùng ngăn xếp
Đầu vào : số trong hệ đếm thập phân n.
Đầu ra : số trong hệ đếm cơ số b tương ứng
1 Chia lấy phần dư n%b được bao nhiêu đẩy vào ngăn xếp.
2 Gán lại n bằng n/b.
3 Lặp lại hai bước 1-2 cho đến khi n = 0.
4 Lấy các giá trị ra khỏi ngăn xếp

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 45 / 71
Ngăn xếp

Ứng dụng 1 : Bài toán đổi cơ số (tiếp)


Minh họa ngăn xếp trong khi chuyển đổi n = 2013 sang số có giá trị tương
đương trong hệ cơ số 8 (hình minh họa trái sang phải)
1 n = 2013
2 n%8 = 5 và n/8 = 251 gán n = 251
3 n%8 = 3 và n/8 = 31 gán n = 31
4 n%8 = 7 và n/8 = 3 gán n = 3
5 n%8 = 3 và n/8 = 0 gán n = 0 (kết thúc)

3
7 7
3 3 3
5 5 5 5

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 46 / 71
Ngăn xếp

Ứng dụng 2 : Bài toán tính giá trị biểu thức số học
Thông thường các công thức toán học được biểu diễn dạng trung tố (infix
notation), trình tự thực hiện các phép toán trong đó được ưu tiên bởi dấu
ngoặc hay các phép toán - nhân chia trước cộng trừ sau.
Ví dụ, công thức số học trung tố

(25 − 14) ∗ 2 + 65 = 87

Tuy nhiên, nhà toán học Jan Lukasiewicz (1878-1956) đã chỉ ra là ta có


thể loại bỏ ngoặc và tính được công thức toán học trên dưới dạng hậu tố
(postfix notation) tương đương như sau

25 14 − 2 ∗ 65+

Ta cũng có thể dùng ngăn xếp để tính giá trị biểu thức hậu tố này

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 47 / 71
Ngăn xếp

Ứng dụng 2 : Bài toán tính giá trị biểu thức số học (tiếp)
Giải thuật tính giá trị biểu thức hậu tố sử dụng ngăn xếp như sau - giả
thuyết ta đã có biểu thức hậu tố cho trước
1 Duyệt biểu thức dạng hậu tố từ trái qua phải
2 Nếu gặp số hạng thì đẩy nó vào ngăn xếp
3 Nếu găp phép toán (+,-,*,/) thì thực hiện phép toán với hai số hạng
được lấy ra đầu ngăn xếp rồi đẩy kết quả lại vào ngăn xếp
4 Tiếp tục duyệt hết biểu thức cho đến khi ngăn xếp chỉ còn giá trị duy
nhất, đây chính là kết quả của biểu thức.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 48 / 71
Ngăn xếp

Ứng dụng 2 : Bài toán tính giá trị biểu thức số học (tiếp)
Minh họa ngăn xếp khi tính biểu thức dạng hậu tố 25 14 − 2 ∗ 65+ khi
duyệt từ trái sang phải
Số hạng 25 được đẩy vào ngăn xếp
Số hạng 14 được đẩy vào ngăn xếp
Với toán hạng - thì lấy hai số hạng 25-14 = 11 sau đó đẩy lại vào
ngăn xếp

14
25 25 11

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 49 / 71
Ngăn xếp

Ứng dụng 2 : Bài toán tính giá trị biểu thức số học (tiếp tục)
Minh họa ngăn xếp khi tính biểu thức dạng hậu tố 25 14 − 2 ∗ 65+ khi
duyệt từ trái sang phải
Số hạng 2 được đẩy vào ngăn xếp
Với toán hạng * thì lấy hai số hạng 11*2 = 22 sau đó lại đẩy vào
ngăn xếp
Số hạng 65 được đẩy vào ngăn xếp
Với toán hạng + thì ta lấy hai số hạng 22+65 = 87 sau đó lại đẩy
vào ngăn xếp (kết thúc duyệt biểu thức dạng hậu tố)

2 65
11 22 22 87

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 50 / 71
Ngăn xếp

Ứng dụng 3 : Chuyển biểu thức dạng trung tố về dạng hậu tố


Bây giờ, ta xét đến việc chuyển biểu thức dạng trung tố về hậu tố gồm
Các toán hạng cộng (+), trừ (-), nhân (*), chia (/) và dấu ngoặc
Các số hạng
Trước hết cũng cần nhắc lại qui tắc tính giá trị biểu thức dạng trung tố
Thứ tự ưu tiên (precedence) : Mũ; Nhân/Chia ; Cộng/Trừ
Qui tắc kết hợp (associativity) : Khi phép toán có cùng mức ưu tiên
I Mũ : Phải qua Trái (PT)
I Nhân/Chia : Trái qua phải (TP)
I Công/Trừ : Trái qua phải (TP)
Dấu ngoặc được thực hiện trước cả thứ tự ưu tiên và qui tắc kết hợp.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 51 / 71
Ngăn xếp

Ứng dụng 3 : Giải thuật Shunting-yard (E.Dijkstra)


1 Duyệt biểu thức từ trái qua phải
2 Nếu gặp số đưa ra lập tức
3 Nếu gặp phép toán o1 thì
I khi phép toán o2 ở đầu ngăn xếp còn thuộc một trong hai tình huống
F o1 có quy tắc kết hợp TP, thứ tự ưu tiên nhỏ hơn bằng o2
F o1 có quy tắc kết hợp PT, thứ tự ưu tiên nhỏ hơn o2
thì đưa o2 ra
I nạp o1 vào
4 Nếu gặp dấu mở ngoặc ( thì nạp nó vào ngăn xếp.
5 Nếu gặp dấu đóng ngoặc ) thì lấy các phần tử ra khỏi ngăn xếp đến
khi gặp dấu mở ngoặc đầu tiên. Lấy nốt dấu ) nhưng không đưa ra.
6 Khi đã duyệt hết biểu thức, đưa tất cả các phép toán còn lại ra khỏi
ngăn xếp.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 52 / 71
Ngăn xếp

Ứng dụng 3 : Chuyển biểu thức dạng trung tố về dạng hậu tố (tiếp)
Minh họa ngăn xếp khi chuyển biểu thức dạng trung tố (25 − 14) ∗ 2 + 65
sang dạng hậu tố, duyệt từ trái qua phải
Gặp dấu mở ngoặc (, nạp nó vào ngăn xếp
Gặp số hạng 25, đưa ra tức thì ⇒ 25
Gặp dấu - đưa vào ngăn xếp
Gặp số hạng 14, đưa ra tức thì ⇒ 25 14

-
( (

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 53 / 71
Ngăn xếp

Ứng dụng 3 : Chuyển biểu thức dạng trung tố về dạng hậu tố (tiếp
tục)
Minh họa ngăn xếp khi chuyển biểu thức dạng trung tố (25 − 14) ∗ 2 + 65
Gặp dấu đóng ngoặc ), đẩy - ra khỏi ngăn xếp cho đến khi gặp dấu
mở ngoặc ) ⇒ 25 14 -
Gặp dấu * thì đẩy vào ngăn xếp
Găp số 2 thì đưa ra tức thì ⇒ 25 14 -2
Gặp dấu + thì đẩy vào ngăn xếp, đưa * ra do * có thứ tự ưu tiên cao
hơn ⇒ 25 14 -2*

-
( * -

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 54 / 71
Ngăn xếp

Ứng dụng 3 : Chuyển biểu thức dạng trung tố về dạng hậu tố (tiếp
tục)
Minh họa ngăn xếp khi chuyển biểu thức dạng trung tố (25 − 14) ∗ 2 + 65
Gặp số hạng 65 thì đưa ra tức thì ⇒ 25 14 - 2*65
Đã duyệt hết và lấy hết phép toán trong ngăn xếp đưa ra ⇒ 25 14 -
2*65+

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 55 / 71
1 Các khái niệm
Kiểu dữ liệu trừu tượng
Cấu trúc dữ liệu
Con trỏ
2 Mảng
3 Danh sách
Định nghĩa
Các cách cài đặt danh sách tuyến tính
4 Ngăn xếp
Định nghĩa
Các cách cài đặt ngăn xếp
Ứng dụng
5 Hàng đợi
Định nghĩa
Các cách cài đặt hàng đợi
Ứng dụng
6 Tổng kết
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 56 / 71
Hàng đợi
Kiểu dữ liệu trừu tượng ngăn xếp (Queue)
Định nghĩa : là danh sách tuyến tính mà phép toán chèn luôn được thực
hiện chỉ được thực hiện ở một phía, gọi là phía sau hay phía cuối (back or
rear), trong khi đó phép toán xóa chỉ được thực hiện ơ phía còn lại, gọi là
phía trước hay đầu (front or head).
Nguyên tắc : Vào trước Ra trước, First-In First-Out (FIFO)
Các phép toán cơ bản
Khởi tạo
Kiểm tra rỗng isEmpty()
Xác định có tràn hay không
Trả lại phần tử đầu hàng front()
Chèn phần tử vào cuối hàng enqueue()
Xóa và lấy ra phần tử đầu hàng dequeue()
In ra hàng đợi print()
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 57 / 71
Hàng đợi
Cài đặt hàng đợi bằng mảng
Sử dụng mảng Q có kích thước N theo thứ tự vòng tròn. Có hai biến để
lưu vị trí đầu và cuối (front và rear) :
f chỉ số của phần tử đầu hàng đợi
r chỉ số của vị trí ở ngay sau vị trí của phần tử cuối cùng của hàng
đợi. Vị trí r được giữ là rỗng.

f r
Q
Cấu hình bình thường

r f
Q
Cấu hình xoay vòng tròn

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 58 / 71
Hàng đợi

Cài đặt hàng đợi bằng mảng


Cài đặt các phép toán cơ bản viết bằng mã giả
Tính kích thước hàng đợi
Function size()
return (N-f+r) mod N
End
Kiểm tra hàng đợi có rỗng không
Function isEmpty()
return (f=r)
End
trong đó mod là phép chia lấy phần dư

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 59 / 71
Hàng đợi

Cài đặt hàng đợi bằng mảng (tiếp)


Cài đặt các phép toán cơ bản viết bằng mã giả
Chèn phần tử vào cuối hàng đợi
Procedure enqueue(o)
if (size=N-1) then
Hiện ra lỗi tràn hàng đợi
else
Q[r] ← o
r ← (r+1) mod N
endif
End

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 60 / 71
Hàng đợi

Cài đặt hàng đợi bằng mảng (tiếp)


Cài đặt các phép toán cơ bản viết bằng mã giả
Lấy phần tử tại đầu hàng đợi
Function dequeue()
o ← NUL
if isEmpty() then
Hiện ra hàng đợi đã rỗng
else
o ← Q[f]
f ← (f+1) mod N
endif
return o
End

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 61 / 71
Hàng đợi

Cài đặt hàng đợi bằng danh sách móc nối


Khi cài đặt hàng đợi bằng danh sách móc nối đơn.
struct qnode{
int element;
struct qnode *next;
} node;
struct queue {node *front; node *back;};
DataType là kiểu dữ liệu cần lưu trữ, được khai báo trước.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 62 / 71
Hàng đợi

Cài đặt hàng đợi bằng danh sách móc nối (tiếp)
Các toán tử được khai báo trong ngôn ngữ C như sau :
// Các hàm thực hiện các toán tử
queue *create();
int isEmpty(queue *q);
int size(queue *q);
void enqueue(queue *q, node *newNode);
node *dequeue(queue *q);
// In ra các phần tử trong hàng đợi
void print(queue *q)

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 63 / 71
Hàng đợi

Cài đặt hàng đợi bằng danh sách móc nối (tiếp)
Các toán tử với mã nguồn C tương ứng
queue *create(){
queue *q;
q = (queue *)malloc(sizeof(queue));
if(q==NULL) return NULL;// Không còn bộ nhớ
q->front = NULL; q->rear = NULL;
return q;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 64 / 71
Hàng đợi

Cài đặt hàng đợi bằng danh sách móc nối (tiếp)
Các toán tử với mã nguồn C tương ứng
int isEmpty(queue *q){
return ((q->front==NULL)&&(q->rear==NULL));
}
int size(queue *q){
queue *ptr=q->front; int count=0;
while(ptr!=NULL){
ptr = ptr->next; count++;
}
return count;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 65 / 71
Hàng đợi

Cài đặt hàng đợi bằng danh sách móc nối (tiếp)
Các toán tử với mã nguồn C tương ứng
void enqueue(queue *q, node *newNode){
/* trong trường hợp ta đã dùng hàm malloc để tạo newNode */
if(!isEmpty()){/* nối vào đuôi hàng đợi */
q->rear->next = *newNode;
q->rear = *newNode;
}
else
{/*nút dữ liệu đầu tiên của hàng đợi*/
q->rear = *newNode;
q->front = *newNode;
}
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 66 / 71
Hàng đợi

Cài đặt hàng đợi bằng danh sách móc nối (tiếp)
Các toán tử với mã nguồn C tương ứng
node *dequeue(queue *q){
node *ptr = q->front;
if(ptr!=NULL){/* có nút dữ liệu trong hàng đợi */
q->front = q->front->next;
if(q->front==NULL) /* là nút dữ liệu cuối cùng */
q->rear = NULL;
ptr->next = NULL;/* ko trỏ kế tiếp vào front nữa */
}
return ptr;/* trả lại con trỏ chưa free bộ nhớ */
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 67 / 71
Hàng đợi

Ứng dụng 1 : Chuyển đổi xâu ký tự số thành số thập phân n


Ý tưởng :
Đưa lần lượt các ký tự số trong xâu ký tự vào hàng đợi Q
Khởi tạo giá trị
n←0
Lấy từng ký tự số ra khởi hàng đợi Q và cập nhật số thập phân n
theo công thức

n ← n × 10 + giá trị ký tự số

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 68 / 71
Hàng đợi

Ứng dụng 1 : Chuyển đổi xâu ký tự số thành số thập phân n (tiếp)


Mã giả của thuật toán như sau :
// Nạp các ký tự số ch vào hàng đợi
do
enqueue(Q,ch)
while(ch = digit)
// khởi tạo giá trị số n
n←0
done ← false
// Vòng lặp cập nhật giá trị số thập phân n
do
n ← n × 10 + giá trị ký tự số
if(not isEmpty(Q)) dequeue(Q,ch) else done ← true endif
while( done or (ch not digit))

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 69 / 71
Hàng đợi

Ứng dụng 2 : Nhận biết xâu ký tự palidromes


Xâu ký tự palidromes là xâu ký tự mà đọc từ trái qua phải cũng giống như
đọc từ phải qua trái. Ví dụ các từ sau đây
"NOON", "DEED", "RADAR", "MADAM","POP"
"ABLE WAS I ERE I SAW ELBA"
"các","cục","tịt","tít","ôtô"...
Ý tưởng giải thuật nhận biết xâu ký tự palidromes :
Cho xâu ký tự vào một hàng đợi và một ngăn xếp
Lấy từng ký tự một từ hàng đợi và một từ ngăn xếp
nếu chúng giống nhau tất cả thì là xâu ký tự palidromes, ngược lại
khi không giống một lần thì không phải là xâu ký tự palidromes.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 70 / 71
Tổng kết

Phân biệt được dữ liệu và cấu trúc dữ liệu (ô dữ liệu + liên kết)
Hiểu được ý nghĩa và các phép toán của các cấu trúc dữ liệu : danh
sách, ngăn xếp, hàng đợi
Các ứng dụng của danh sách, ngăn xếp, hàng đợi

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 71 / 71
Chương 4 : Cây

Trịnh Anh Phúc1

1 Bộ môn Khoa Học Máy Tính, Viện CNTT & TT,


Trường Đại Học Bách Khoa Hà Nội.

Ngày 13 tháng 7 năm 2021

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 1 / 59
Giới thiệu
1 Định nghĩa và các khái niệm
Định nghĩa cây
Các thuật ngữ chính
Cây có thứ tự
Cây có nhãn
2 Cây nhị phân
Định nghĩa và tính chất
3 Các ứng dụng của cây
Cây nhị phân biểu thức
Cây quyết định
Mã Huffman
Cây gọi đệ qui
4 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 2 / 59
Định nghĩa và các khái niệm

Định nghĩa cây


Cây bao gồm các nút, có một nút đặt biệt được gọi là nút gốc (root ) và
các cạnh nối các nút. Cây được định nghĩa đệ qui như sau
Bước cơ sở : một nút r được coi là cây và r được gọi là gốc cây.
Bước đệ qui : Giả sử T1 , T2 , · · · , Tk là các cây với gốc là
r1 , r2 , · · · , rk , ta có thể xây dựng cây mới bằng cách đặt r làm nút
cha (parent) của các nút r1 , r2 , · · · , rk . Trong cây mới tạo ra r là gốc
và T1 , T2 , · · · , Tk là các cây con của gốc r . Các nút r1 , r2 , · · · , rk
được gọi là con của nút r .

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 3 / 59
Định nghĩa và các khái niệm

Định nghĩa cây (tiếp)


Hình minh họa định nghĩa đệ qui của cây

r1 r2 ... rk

T1 T2 ... Tk

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 4 / 59
Định nghĩa và các khái niệm

Các ứng dụng của dữ liệu trừu tượng cây


Cây trong ứng dụng thực tế
Biểu đồ lịch thi đấu
Cây gia phả
Biều đồ phân cấp quản lý
Cây thư mục quản lý file
Cây biểu thức
....
Sau đây là một vài hình ảnh minh họa các ứng dụng này

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 5 / 59
Ứng dụng cây gia phả

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 6 / 59
Ứng dụng biểu đồ phân cấp quản lý

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 7 / 59
Ứng dụng cây thư mục

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 8 / 59
Cây

Các thuật ngữ chính


Nút - node
Gốc - root
Lá - leaf
Con - child
Cha - parent
Tổ tiên - ascentors
Hậu duệ - descendants
Anh em - sibling
Chiều cao - hight
Nút trong - internal node
Đường đi - path

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
Ngày
Hà13
Nội.
tháng
) 7 năm 2021 9 / 59
Cây
Phân loại các nút trong cây
a

b c d

e f g h

i j

Chú thích : Nút gốc mầu xanh thẫm, nút lá mầu xanh lá cây còn nút
trong mầu trắng.
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 10 / 59
Cây
Các nút cùng cha gọi là các nút anh&em. Trong hình là ba nút b,c,d có
cùng nút cha là a, được đánh dấu bởi hình elíp đỏ.

b c d

e f g h

i j

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 11 / 59
Cây
Cây con của nút gốc a,

b c d

e f g h

i j

Chú thích : Vòng tròn bao mầu đỏ chỉ ra một cây con của nút gốc a.
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 12 / 59
Cây
Đường đi trên cây từ nút gốc a đến các nút lá i và h (gạch nét dứt mầu
đỏ). Đường thứ nhất {a,b,f,i} và đường thứ hai là {a,d,h}.

b c d

e f g h

i j

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 13 / 59
Cây
Độ cao của cây và độ sâu của cây. Do nút gốc có mức 1 nên nút lá xa nhất
k có mức chính là độ cao và độ sâu của cây, vậy cây trên có độ cao là 5.

a Mức=1

b c d

e f g h

i j

k Mức=5

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 14 / 59
Cây
Bậc (degree) của một nút là số nút con của nó. Vậy nút gốc a có bậc 3
trong khi nút lá như h luôn có bậc 0.

a Bậc=3

b c d

e f g h Bậc=0

i j

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 15 / 59
Cây

Cây có thứ tự
Thứ tự của các nút trên cây : Các nút con của một nút thường được
sắp xếp theo thứ tự từ trái sang phải

a a

b c c b

Như vậy rõ ràng hai cây trên khác nhau do thứ tự nút con của nút a là
khác nhau. Hay nút b được xếp trước nút c trong cây bên trái, trong khi
nó được xếp sau nút c trong cây bên phải.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 16 / 59
Cây

Xếp thứ tự các nút


Có ba cách thông thường để xác định thứ tự các nút
1 Thứ tự trước (Preorder)
2 Thứ tự giữa (Inorder)
3 Thứ tự sau (Postorder)

r1 r2 ... rk

...

T1 T2 Tk

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 17 / 59
Cây

Thứ tự trước - Preorder traversal


Gốc r của cây
tiếp đến là các nút của T1 được duyệt theo thứ tự trước
tiếp đến là các nút của T2 được duyệt theo thứ tự trước...
và cuối cùng là các nút của Tk được duyệt theo thứ tự trước

r1 r2 ... rk

...

T1 T2 Tk

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 18 / 59
Cây

Thứ tự sau - Postorder traversal


các nút của cây T1 theo thứ tự sau
tiếp đến là các nút của T2 được duyệt theo thứ tự sau...
tiếp đến là các nút của Tk được duyệt theo thứ tự sau
sau cùng là nút gốc r

r1 r2 ... rk

...

T1 T2 Tk

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 19 / 59
Cây

Thứ tự giữa - Inorder traversal


các nút của cây T1 theo thứ tự giữa
tiếp đến nút gốc r
tiếp đến các nút của cây T2 , · · · , Tk mỗi nhóm nút được xét theo thứ
tự giữa.

r1 r2 ... rk

...

T1 T2 Tk

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 20 / 59
Cây

Cây có nhãn - labaled tree


Thông thường người ta gán cho mỗi nút nột nhãn hoặc một giá trị, cũng
giống như ta gán mỗi nút trong danh sách tuyến tính một phần tử
(element). Nghĩa là nhãn của nút không chỉ là tên gọi mà mang ý nghĩa
giá trị của nút đó. Ví dụ rõ nhất là cây biểu thức ...

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 21 / 59
Cây

Cây biểu thức - expression tree

+ -

a c
b a
Biểu thức : (a+b)*(a-c)

Qui tắc biểu diễn cây biểu thức là :


Mỗi nút lá là một số hạng và chỉ gồm số hạng đó
Mỗi nút trong được gán một phép toán. Với phép toán hai ngôi E1 q
E2 , ví dụ của q = {+,-,*,/}, thì cây con trái biểu diễn biểu thức E1
còn cây con phải biểu diễn E2 .

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 22 / 59
1 Định nghĩa và các khái niệm
Định nghĩa cây
Các thuật ngữ chính
Cây có thứ tự
Cây có nhãn

2 Cây nhị phân


Định nghĩa và tính chất

3 Các ứng dụng của cây


Cây nhị phân biểu thức
Cây quyết định
Mã Huffman
Cây gọi đệ qui

4 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 23 / 59
Cây nhị phân

Cây nhị phân - binary tree


Định nghĩa : Cây nhị phân là cây mà mỗi nút có nhiều nhất là hai nút con.
Vì mỗi nút chỉ có hai con nên ta sẽ gọi chúng là con trái và con phải. Chú
ý là cây nhị phân giản lược so với cây tổng quát nên ta không cần xác
định thứ tự các nút con.
Tính chất của cây nhị phân
Số đỉnh lớn nhất ở trên mức i của cây nhị phân là 2i−1 , với i ≥ 1
Một cây nhị phân với chiều cao h có không quá 2h − 1 nút, với h ≥ 1
Một cây nhị phân có n nút có chiều cao tối thiểu là dlog2 (n + 1)e

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 24 / 59
Cây nhị phân

Minh họa ba cây nhị phân


a

a a
b
b b
c d
c d c d

e e e

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 25 / 59
Cây nhị phân

Cây nhị phân đầy đủ - full binary tree


Định nghĩa : Cây nhị phân đầy đủ là cây nhị phân mà mỗi nút có đúng
hai nút con đồng thời các nút lá cùng độ sâu.

b c

d g
e f

Tính chất của cây nhị phân đầy đủ


Cây nhị phân đầy đủ với độ sâu d có 2d − 1 nút.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 26 / 59
Cây nhị phân

Cây nhị phân hoàn chỉnh - complete binary tree


Định nghĩa Cây nhị phân độ sâu d thỏa mãn :
là cây nhị phân đầy đủ nếu không tính đến các nút ở độ sâu d, hay
mức cao nhất.
tất cả các nút tại độ sâu d lệch sang trái nhất có thể.
Tính chất
Cây nhị phân hoàn chỉnh có độ sâu d thì số nút của nó nằm trong
khoảng từ 2d−1 đến 2d − 1

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 27 / 59
Cây nhị phân

Cây nhị phân hoàn chỉnh (tiếp)


Ví dụ về cây nhị phân hoàn chỉnh

b c

d g
e f
h
i k
j

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 28 / 59
Cây nhị phân

Cây nhị phân cân đối - balanced binary tree


Định nghĩa Cây nhị phân được gọi là cân đối nếu chiều cao cây con trái
và cây con phải của các nút là không lệch nhau quá một đơn vị.
a

b a
a
c b c
b c
d e d
d
e f e f

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 29 / 59
Cây nhị phân

Biểu diễn cây nhị phân


Để biểu diễn cây nhị phân trong máy tính, ta cũng có hai cách
sử dụng mảng
sử dụng con trỏ
Trong trường hợp cây nhị phân hoàn chỉnh, sử dụng cách biểu diễn này ta
có thể cài đặt hiệu quả nhiều phép toán trên cây, cả phép toán đối với nút
con.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 30 / 59
Cây nhị phân
Biểu diễn cây nhị phân hoàn chỉnh với mảng
Chú ý, các nút được đánh chỉ số trong mảng từ trên xuống dưới và từ trái
qua phải. Với chỉ sô i = 1, 2, · · · , n với n là số nút trên cây

b c

d g
e f
h
i k
j

a b c d e f g h i j k

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 31 / 59
Cây nhị phân

Biểu diễn cây nhị phân hoàn chỉnh với mảng (tiếp)
Các phép toán trên cây nhị phân hoàn chỉnh biểu diễn bằng mảng A[i] với
chỉ số i = 1, 2, · · · , n với n là số nút trên cây.

Để tìm Sử dụng Hạn chế


Con trái của A[i] A[2 ∗ i] 2∗i ≤n
Con phải của A[i] A[2 ∗ i + 1] 2∗i +1≤n
Cha của A[i] A[i/2] i >1
Gốc A[1] A khác rỗng
Nút A[i] là lá Đúng 2∗i >n

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 32 / 59
Cây nhị phân
Biểu diễn cây nhị phân bằng con trỏ
Mỗi nút trong cây nhị phân sẽ gồm ba thành phần
con trỏ đến con trái (left)
phần tử chứa kiểu dữ liệu (item)
con trỏ đến con phải (right)

left Item right

Cài đặt trong C


struct Tnode{
DataType Item;
struct Tnode *left;
struct Tnode *right;
}
typedef struct Tnode treeNode;
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 33 / 59
Cây nhị phân
Biểu diễn cây nhị phân bằng con trỏ
Các phép toán cơ bản cây nhị phân có kiểu dữ liệu số nguyên
struct Tnode{
int Item;
struct Tnode *left;
struct Tnode *right;
}
typedef struct Tnode treeNode;
treeNode *makeTreeNode(int x);
void freeTree(treeNode *tree);
void printPreorder(treeNode *tree);
void printPostorder(treeNode *tree);
void printInorder(treeNode *tree);
int countNode(treeNode *tree);
int depth(treeNode *tree);

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 34 / 59
Cây nhị phân

Biểu diễn cây nhị phân bằng con trỏ với phép toán tạo nút mới
treeNode *makeTreeNode(int x){
treeNode *newNode = NULL;
newNode = (treeNode*)malloc(sizeof(treeNode));
if(newNode==NULL){
printf("Het bo nho \n");
exit(1);
}else{
newNode->left = NULL;
newNode->right = NULL;
newNode->Item = x;
}
return newNode;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 35 / 59
Cây nhị phân

Biểu diễn cây nhị phân bằng con trỏ với phép toán đếm số nút
int countNodes(treeNode *tree){
if(tree==NULL) return 0;
else{
int ld = countNodes(tree->left);
int rd = countNodes(tree->right);
return 1+ld+rd;
}
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 36 / 59
Cây nhị phân

Biểu diễn cây nhị phân bằng con trỏ với phép toán tính độ sâu
int depth(treeNode *tree){
if(tree==NULL) return 0;
int ld = depth(tree->left);
int rd = depth(tree->right);
return 1+(ld>rd ? ld : rd);
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 37 / 59
Cây nhị phân

Biểu diễn cây nhị phân bằng con trỏ với phép toán loại bỏ cây
void freeTree(treeNode *tree){
if(tree=NULL) return;
freeTree(tree->left);
freeTree(tree->right);
free(tree);
return;
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 38 / 59
Cây nhị phân
Biểu diễn cây nhị phân bằng con trỏ với phép toán duyệt cây theo thứ
tự trước
Duyệt đệ qui theo thứ tự trước
Thăm nút
Thăm cây con trái theo thứ tự trước
Thăm cây con phải theo thứ tự trước
Mã nguồn ngôn ngữ C
void printPreorder(treeNode *tree){
if(tree!=NULL)
{
printf("%5d",tree->Item);
printPreorder(tree->left);
printPreorder(tree->right);
}
}
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 39 / 59
Cây nhị phân
Biểu diễn cây nhị phân bằng con trỏ với phép toán duyệt cây theo thứ
tự giữa
Duyệt đệ qui theo thứ tự giữa
Thăm cây con trái theo thứ tự giữa
Thăm nút
Thăm cây con phải theo thứ tự giữa
Mã nguồn ngôn ngữ C
void printInorder(treeNode *tree){
if(tree!=NULL)
{
printInorder(tree->left);
printf("%5d",tree->Item);
printInorder(tree->right);
}
}
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 40 / 59
Cây nhị phân
Biểu diễn cây nhị phân bằng con trỏ với phép toán duyệt cây theo thứ
tự sau
Duyệt đệ qui theo thứ tự sau
Thăm cây con trái theo thứ tự sau
Thăm cây con phải theo thứ tự sau
Thăm nút
Mã nguồn ngôn ngữ C
void printPostrder(treeNode *tree){
if(tree!=NULL)
{
printPostorder(tree->left);
printPostorder(tree->right);
printf("%5d",tree->Item);
}
}
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 41 / 59
Cây nhị phân

Minh họa ba phép duyệt (trước, giữa, sau) của cây nhị phân dưới đây
Duyệt trước : a,b,d,h,i,e,j,k,c,f,g
Duyệt giữa : h,d,i,b,j,e,k,a,f,c,g
Duyệt sau : h,i,d,j,k,e,b,f,g,c,a

b c

d g
e f
h
i k
j

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 42 / 59
1 Định nghĩa và các khái niệm
Định nghĩa cây
Các thuật ngữ chính
Cây có thứ tự
Cây có nhãn

2 Cây nhị phân


Định nghĩa và tính chất

3 Các ứng dụng của cây


Cây nhị phân biểu thức
Cây quyết định
Mã Huffman
Cây gọi đệ qui

4 Tổng kết

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 43 / 59
Cây nhị phân

Ứng dụng 1 : cây nhị phân biểu thức - expression binary tree
Cây biểu thức nhị phân trong đó :
mỗi nút lá chứa một toán hạng
mỗi nút trong chứa phép toán một ngôi
Các cây con trái và các cây con phải chứa hai vế của biểu thức phép
toán hai ngôi.
Các mức thể hiện mức độ ưu tiên của phép toán :
Mức của các nút trên cây cho biết trình tự thực hiện các phép toán
(lưu ý, không sử dụng dấu ngoặc trong cây nhị phân biểu thức)
Các phép toán mức cao được thực hiện trước
Phép toán ở gốc được thực hiện sau cùng

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 44 / 59
Cây nhị phân

Ứng dụng 1 : cây nhị phân biểu thức - expression binary tree (tiếp)
Duyệt cây nhị phân biểu thức có thể cho ta các biểu thức dưới dạng
trung tố, tiền tố và hậu tố
Duyệt cây biểu thức theo thứ tự trước (preorder) cho ta biểu thức
dưới dạng tiền tố.
Duyệt cây biểu thức theo thứ tự giữa (inorder) cho ta biểu thức dưới
dạng trung tố.
Duyệt cây biểu thức theo thứ tự sau (postorder) cho ta biểu thức
dưới dạng hậu tố.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 45 / 59
Cây nhị phân

Ứng dụng 1 : cây nhị phân biểu thức (tiếp)


Ví dụ minh họa

+ -

a c
b a

Biểu thức tiền tố : * + a b - a c


Biểu thức trung tố : (a+b)*(a-c)
Biểu thức hậu tố : a b + a c - *

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 46 / 59
Cây quyết định - decision tree
Cây quyết định là một cây mà mỗi nút trong nó là một truy vấn đối với dữ
liệu. Các cạnh của cây tương ứng với khả năng trả lời của câu hỏi. Mỗi lá
của nó tương ứng với một đầu ra.
Để xác định quyết định, dữ liệu được đi vào từ gốc cây - truy vấn ở gốc.
Sau đó đi xuống đến lá thì biết được đầu ra - thực chất là một quyết định
cuối cùng.
Các ứng dụng
Quyết định phân loại
Quyết định hỏi/đáp trong marketing
Cây quyết định mờ (fuzzy decision tree) là một mô hình hiệu quả
trong lĩnh vực học máy.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 47 / 59
Cây quyết định - decision tree (tiếp)
Bài toán tra từ điển Cho một mảng gồm n số được sắp xếp theo thứ tự
tăng dần và một số x. Cẫn xác định xem x có mặt trong mảng đã cho hay
không. Nếu câu trả lời khẳng định thì cần chỉ ra vị trí của x trong mảng.
Thực ra người ta gọi đây là bài toán tra từ điển, bởi cuốn từ điển được
phân chia theo thứ tự alphabet từ A đến Z. Khi tra từ ta lật giở theo mục
từ để tìm đến trang từ điển cần tra cứu.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 48 / 59
Xét mảng A = (2,3,5,7,11,13,17,19) thì cây quyết định có dạng như sau

x<11?
S
Đ
x<5? x<17?

S S
Đ Đ

x<3? x<7? x<13? x<19?

S S S S
Đ Đ Đ Đ

x=2? x=3? x=5? x=7? x=11? x=13? x=17? x=19?


Đ : Đúng, S: Sai

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 49 / 59
Mã Huffman
Mã Huffman - Huffman code
Giả sử trong văn bản có bảng chữ cái C , với mỗi chữ cái c ∈ C ta biết tần
suất xuất hiện của nó trong văn bản là f (c). Cần tìm cách mã hóa văn
bản sử dụng ít bộ nhớ nhất. Có hai loại mã hóa hay dùng
Mã hóa với độ dài cố định có đặc điểm dễ mã hóa cũng như dễ giải
mã nhưng đòi hỏi bộ nhớ phải lớn
Mã phi tiền tố (prefix free code) là cách mã hóa mỗi ký tự c bởi một
xâu nhị phân code(c) sao cho mã của một ký tự bất kỳ không là
đoạn đầu của bất cứ mã của ký tự nào khác trong số các ký tự còn
lại. Tuy đòi hỏi việc mã hóa (code) và giải mã (decode) phức tạp
nhưng lại đòi hỏi ít bộ nhớ hơn.
Mã hóa độ dài cố định có ví dụ như mã ASCII (độ dài cố định 8 bit). Ngoài
ra ta cũng có mã hóa Morse, căn cứ vào thống kê tần số của các chữ cái
trong từ điển tiếng Anh. Chú ý là mã Morse không phải là mã phi tiền tố.
Trong khi mã Huffman được trình bầy dưới đây lại là mã phi tiền tố.
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 50 / 59
Mã Huffman (tiếp)

Mã Huffman (tiếp)
Mỗi mã phi tiền tố có thể biểu diễn bởi một cây nhị phân T mà mỗi lá
của nó tương ứng với một chữ cái và cành của nó được gán cho một trong
hai số 1 và 0. Mã của một chữ cái c là một dãy nhị phân gồm các số gán
cho các cạnh trên đường đi từ gốc đến là tương ứng với c.

Bài toán
Tìm cách mã hóa tối ưu, tức cây nhị phân T làm tối thiểu hóa tổng độ
dài có trọng số X
B(T ) = f (c) × depth(c)
c∈C

trong đó depth(c) là độ dài đường đi từ gốc đến lá tương ứng vởi ký tự c


còn f (c) là tần số xuất hiện của ký tự c.

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 51 / 59
Mã Huffman (tiếp)

Cấu trúc dữ liệu và giải thuật Mã Huffman (tiếp)

2021-07-13 Các ứng dụng của cây


Mỗi mã phi tiền tố có thể biểu diễn bởi một cây nhị phân T mà mỗi lá
của nó tương ứng với một chữ cái và cành của nó được gán cho một trong
hai số 1 và 0. Mã của một chữ cái c là một dãy nhị phân gồm các số gán
cho các cạnh trên đường đi từ gốc đến là tương ứng với c.

Mã Huffman Bài toán


Tìm cách mã hóa tối ưu, tức cây nhị phân T làm tối thiểu hóa tổng độ
dài có trọng số

Mã Huffman (tiếp)
X
B(T ) = f (c) × depth(c)
c∈C

trong đó depth(c) là độ dài đường đi từ gốc đến lá tương ứng vởi ký tự c


còn f (c) là tần số xuất hiện của ký tự c.

Lý do để tối thiểu hóa hàm trên đơn giản là làm giảm số bit cần mã hóa
khi truyền thông tin bảng chữ C lên đường truyền.
Mã Huffman (tiếp)
Thuật toán
Ý tưởng thuật toán : chữ cái có tầm suất nhỏ hơn cần được gán cho lá có
khoảng cách đến gốc là lớn hơn. Ngược lại, chữ cái có tần suất xuất hiện
lớn hơn cần gần được gán gần nút gốc hơn.

Thuật toán : Mã hóa (code)


Procedure Huffman(C , f )
n ← |C |; /* Gán cho n số các ký tự trong C */
Q ← C;
for i ← 1 to n do
x,y ← 2 chữ cái có tần xuất nhỏ nhất trong Q;
/*Tạo nút p là nút cha của x,y với */
f(p) ← f(x) + f(y);
Q ← Q loại bỏ {x,y};Q ← Q thêm p;
endfor
End
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 52 / 59
Mã Huffman (tiếp)

Cấu trúc dữ liệu và giải thuật Thuật toán


Ý tưởng thuật toán : chữ cái có tầm suất nhỏ hơn cần được gán cho lá có

2021-07-13 Các ứng dụng của cây


khoảng cách đến gốc là lớn hơn. Ngược lại, chữ cái có tần suất xuất hiện
lớn hơn cần gần được gán gần nút gốc hơn.

Thuật toán : Mã hóa (code)

Mã Huffman Procedure Huffman(C , f )


n ← |C |; /* Gán cho n số các ký tự trong C */
Q ← C;
for i ← 1 to n do

Mã Huffman (tiếp) x,y ← 2 chữ cái có tần xuất nhỏ nhất trong Q;
/*Tạo nút p là nút cha của x,y với */
f(p) ← f(x) + f(y);
Q ← Q loại bỏ {x,y};Q ← Q thêm p;
endfor
End

Mã xây dựng theo thuật toán trên gọi là mã Huffman. Giải thuật có thởi
gian cài là O(n log n) vởi n là số chữ cái trong C.
Mã Huffman (tiếp)

Ví dụ về mã Huffman
Cho xâu chữ không dấu : "Đai hoc Bach khoa Hanoi" có được bảng chữ
có cả tần số xuất hiện giảm dần của ký tự như sau

Ký tự ’a’ ’ ’ ’h’ ’o’ ’c’ ’i’ ’Đ’ ’K’ ’H’ ’B’ ’n’
f(c) 4 4 3 3 2 2 1 1 1 1 1

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 53 / 59
Mã Huffman (tiếp)

23 1
9 0 14
1 1
0 0
5 4 6 8
1 1 1 1
0 0 0 0
2 3 ’c’ ’i’ ’h’ ’o’ ’a’ ’ ’

1 1
0 0

’Đ’ ’K’ 2 ’n’


1
0
’H’ ’B’
Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu
CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 54 / 59
Mã Huffman (tiếp)

Cấu trúc dữ liệu và giải thuật 23 1

2021-07-13
9 0 14
1 1

Các ứng dụng của cây 5


1
0
4
1
6
1
0
8
1

Mã Huffman 2
0
3 ’c’
0
’i’ ’h’
0
’o’ ’a’
0
’ ’

Mã Huffman (tiếp) 0
1
0
1

’Đ’ ’K’ 2 ’n’


1
0
’H’ ’B’

Mã hóa Huffman cho mỗi ký tự (nút lá) chính là mã nhị phân đường đi
từ gốc đến lá. Các nút trong có số chỉ chính tần số của nút p được thêm
vào tập Q trong giải thuật mã hóa Huffman. Mã hóa của mỗi ký tự là dãy
bit {0,1} nằm trên đường đi từ gốc đến lá, tương ứng từng ký tự.
Mã Huffman (tiếp)

Giải mã Huffman
Procedure Huffman-Decode(B)
/* Trong đó B là xâu nhị phân mã hóa văn bản theo mã hóa Huffman */
<Khởi động p là gốc của cây Huffman>
while <chưa đạt đến kết thúc của xâu B> do
x ← bit tiếp theo trong xâu B
if (x=0) then p ← con trái của p else p ← con phải của p endif
if (p là nút lá) then
<hiển thị ký tự tương ứng nút lá>
<đặt lại p làm gốc của cây Huffman>
endif
endwhile
End

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 55 / 59
Cây gọi đệ qui

Cây gọi đệ qui


Đây là một công cụ quan trọng khi phân tích giải thuật đệ qui, cây gọi đệ
qui được định nghĩa như sau
Nút gốc r của cây là lần gọi đầu của giải thuật
Nút lá của cây tương ứng bước cơ sở
Nhánh cây từ nút cha f (n + 1) đến các nút con f (k) với k ≤ n tương
ứng bước gọi đệ qui của hàm f (n + 1)

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 56 / 59
Cây gọi đệ qui (tiếp)

Ví dụ tính dãy số Fibonnacci


Dãy số Fibonacci đc định nghĩa đệ qui như sau :
Bước cơ sở : F(0) = 1, F(1) = 1;
Bước đệ qui : F(n) = F(n-1) + F(n-2) với n ≥ 2
Hàm đệ qui viết bằng ngôn ngữ C
int FibRec(int n){
if(n<=1) return 1;
else return FibRec(n-1) + FibRec(n-2);
}

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 57 / 59
Cây gọi đệ qui (tiếp)

Ví dụ tính dãy số Fibonnacci (tiếp)


FibRec(4)

FibRec(3) FibRec(2)

FibRec(2) FibRec(1) FibRec(1) FibRec(0)

FibRec(1) FibRec(0)
Cây gọi đệ qui tính số Fibonnacci với lần gọi đầu FibRec(4)

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 58 / 59
Tổng kết

Định nghĩa đệ qui và các thuật ngữ cấu trúc dữ liệu cây
Các phép toán trên cấu trúc dữ liệu cây
Cách biểu diễn CTDL cây trong máy tính
Cây nhị phân định nghĩa và tính chất
Các ứng dụng của cây nhị phân

Trịnh Anh Phúc ( Bộ môn Khoa Học Máy Tính, ViệnCấu


CNTT
trúc&dữTT,
liệu Trường
và giải thuật
Đại Học Bách Khoa
NgàyHà
13Nội.
tháng
) 7 năm 2021 59 / 59

You might also like