You are on page 1of 50

CẤU TRÚC DỮ LIỆU

VÀ THUẬT TOÁN
Data Structures and Algorithms

NguyỄN ĐỨC NGHĨA


Bộ môn Khoa học Máy tính
Đại học Bách khoa Hà nội

Tel: 0438696121 (Off), 0903210111 (Mob)


nghiand@soict.hut.edu.vn
Chương 1

CÁC KIẾN THỨC CƠ BẢN

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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 .

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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;
}
}

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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) 
 
2 k 1
k ( k  1)  k 
2  k 1
k  
k 1  2 6

2 
n3 n 2 n
  
6 2 3

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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;
}
}

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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).

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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;
}

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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;
}

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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);
}
}

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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 ( )  n  2T ( )n n 1
2 2

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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 !

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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.

• Các bảng trình bày dưới đây cho thấy thời gian tính với
giả thiết máy tính có thể thực hiện 108 phép cộng trong 1
giây

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Thời gian tính

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Thời gian tính

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Bảng qui đổi thời gian

• Bảng sau đây dùng để tính thời gian thực hiện

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Bài toán mở đầu

• Với n nhỏ thời gian tính là không đáng kể.


• Vấn đề trở nên nghiêm trọng hơn khi n > 106. Lúc
đó chỉ có thuật toán thứ ba là có thể áp dụng được
trong thời gian thực.
• Còn có thể làm tốt hơn nữa không?
• Có thể đề xuất thuật toán chỉ đòi hỏi n phép cộng!

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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).

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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 .

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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.
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Vòng đời của phần mềm


The Life Cycle of Software

• Vòng đời của phần mềm

– Là một quá trình dài và liên tục

– Đòi hỏi để phát triển một phần mềm có chất lượng tốt

– Lập trình viên có thể di chuyển từ một pha trong vòng đời
sang bất kỳ pha nào còn lại

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Vòng đời của phần mềm
The Life Cycle of Software

Vòng đời của phần mềm như là một bánh lái có thể quay từ một pha đến một pha
khác bất kỳ
Nguyễn Đức Nghĩa - Bộ 1-35
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT
môn KHMT ĐHBKHN

Vòng đời của phần mềm


The Life Cycle of Software

9 pha:
• Phase 1: Chỉ rõ đặc điểm kỹ thuật (Specification) (đặc tả)
• Phase 2: Thiết kế (Design)
• Phase 3: Phân tích rủi ro (Risk Analysis)
• Phase 4: Kiểm thử (Verification)
• Phase 5: Lập trình (Coding)
• Phase 6: Test thử (Testing)
• Phase 7: Tinh chế lời giải (Refining the Solution)
• Phase 8: Sản xuất (Production)
• Phase 9: Bảo trì (Maintenance)

Nguyễn Đức Nghĩa - Bộ 1-36


Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT
môn KHMT ĐHBKHN
Vòng đời của phần mềm
The Life Cycle of Software

• Phase 1: Đặc tả (Specification)


– Các khía cạnh của bài toán cần chỉ rõ:
• Dữ liệu đầu vào là gì (What is the input data?)
• Dữ liệu nào là đúng đắn, là không đúng đắn?
• Ai là người sử dụng phần mềm và giao diện người dùng cần được
thiết kế như thế nào?
• Cần phát hiện những lỗi gì và cần thông báo như thế nào về chúng?
• Có thể có các giả thiết nào?
• Có những trường hợp đặc biệt nào?
• Dạng của dữ liệu đưa ra như thế nào?
• Cần có các tài liệu gì?
• Cái gì cần phát triển trong tương lai?
– Chương trình mẫu (Chương trình mô phỏng dáng điệu của một phần
của sản phẩm phần mềm cần phát triển)
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Vòng đời của phần mềm


The Life Cycle of Software

• Phase 2: Thiết kế (Design). Quá trình thiết kế


bao gồm:
– Chia chương trình ra thành các modules (Modules:
là các đơn vị chương trình độc lập)
– Chỉ rõ mục đích của mỗi module
– Chỉ rõ dòng dữ liệu trong các modules
– Xác định giao diện (Interfaces - Cơ cấu giao tiếp
giữa các mô đun)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Vòng đời của phần mềm
The Life Cycle of Software

• Phase 3: Phân tích rủi ro (Risk Analysis)


• Phase 4: Kiểm thử (Verification)
– Chứng minh tính đúng đắn của thuật toán bằng các phương pháp hình thức, …
• Phase 5: Cài đặt (Coding)
– Liên quan đến việc chuyển thiết kế sang một ngôn ngữ lập trình cụ thể
– Loại trừ các lỗi ngữ pháp
• Phase 6: Test thử (Testing)
– Liên quan đến việc loại bỏ các lỗi logic
– Dữ liệu test phải bao gồm:
• Dữ liệu đúng đắn với kết quả biết trước
• Dữ liệu không đúng đắn
• Dữ liệu ngẫu nhiên
• Dữ liệu thực tế

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Vòng đời của phần mềm


The Life Cycle of Software

• Phase 7: Tinh chế lời giải (Refining the Solution)


– Do chương trình được phát triển với những giả thiết nhất định nên cần
tìm cách giảm nhẹ các giả thiết được bổ sung đối với đầu vào, đầu ra
– Bổ sung thêm các chức năng
– Tăng các biện pháp kiểm tra lỗi
• Phase 8: Xuất xưởng (Production)
– Bàn giao sản phẩm cho người dùng.
– Người dùng sử dụng phần mềm
• Phase 9: Bảo trì (Maintenance)
– Sửa chữa các lỗi do người sử dụng phát hiện.
– Bổ sung thêm chức năng.
– Cải tiến một số bộ phận để đáp ứng yêu cầu của người dùng tốt hơn

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Độ 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.
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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.
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Ký hiệu tiệm cận
Asymptotic Notation

Q, W, 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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Ký hiệu Q

Đố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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Ký hiệu W

Đối với hàm g(n) cho trước, ta ký hiệu W(g(n)) là tập các hàm
W(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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Liên hệ giữa , W, 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) = W(g(n))
tức là
(g(n)) = O(g(n))  W(g(n))

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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) O(f(n))
• “Thời gian tính là W(f(n))” hiểu là: Đánh giá trong tình huống tốt nhất
(best case) là W(f(n)). Thường nói: “Đánh giá thời gian tính trong
tình huống tốt nhất là W(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)  W(f(n))

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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
W(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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Đồ thị của một số hàm cơ bản

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Giá trị của các hàm cơ bản

n logn n nlogn n2 n3 2n

4 2 4 8 16 64 16

8 3 8 24 64 512 256

16 4 16 64 256 4,096 65,536

32 5 32 160 1,024 32,768 4,294,967,296

64 6 64 384 4,094 262,144 1.84 * 1019

128 7 128 896 16,384 2,097,152 3.40 * 1038

256 8 256 2,048 65,536 16,777,216 1.15 * 1077

512 9 512 4,608 262,144 134,217,728 1.34 * 10154

1024 10 1,024 10,240 1,048,576 1,073,741,824 1.79 * 10308

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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) = W(g(n))  a  b

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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Liên hệ với khái niệm giới hạn

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


n

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


n

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


n

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


n

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


n

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


n
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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) = W(g(n)) & g(n) = W(h(n))  f(n) = W(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) = W(f(n))

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Ví dụ

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

• log3(n2) log2(n3)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Ví dụ

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

• log3(n2) log2(n3)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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) = W(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) = W(g(n))
– f(n) = n log n + n; g(n) = log n f(n) = W(g(n))
– f(n) = 10; g(n) = log 10 f(n) = (g(n))
– f(n) = 2n; g(n) = 10n2 f(n) = W(g(n))
– f(n) = 2n; g(n) = 3n f(n) = O(g(n))

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Ví dụ

– 2n2 = O(n3): 2n2 ≤ cn3  2 ≤ cn  c = 1 and n0= 2

– n2 = O(n2): n2 ≤ cn2  c ≥ 1  c = 1 and n0= 1

– 1000n2+1000n = O(n2):

1000n2+1000n ≤ cn2  c=1001 and n0 = 1000

– n = O(n2): n ≤ cn2  cn ≥ 1  c = 1 and n0= 1

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Ví dụ

– 5n2 = W(n)
 c, n0 sao cho: 0  cn  5n2  cn  5n2  c = 1 và n0 = 1

– 100n + 5 ≠ W(n2)
Giả sử:  c, n0 sao cho: 0  cn2  100n + 5.
Ta có: 100n + 5  100n + 5n ( n  1) = 105n
Suy ra: cn2  105n  n(cn – 105)  0
Do n dương  cn – 105  0  n  105/c
 vô lý: n không thể nhỏ hơn hằng số

– n = W(2n), n3 = W(n2), n = W(logn)


Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Ví dụ

Chứng minh các khẳng định:

n2/2 – n/2 = (n2)

• ½ n2 - ½ n ≤ ½ n2 n ≥ 0  c2= ½

• ½ n2 - ½ n ≥ ½ n2 - ½ n * ½ n ( n ≥ 2 ) = ¼ n2

 c1= ¼

n ≠ (n2): c1 n2 ≤ n ≤ c2 n2

 chỉ đúng với: n ≤ 1/c1


Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT
Ví dụ

6n3 ≠ (n2): c1 n2 ≤ 6n3 ≤ c2 n2

 chỉ đúng với: n ≤ c2 /6

n ≠ (log n): c1 log n ≤ n ≤ c2 log n

 c2 ≥ n/log n,  n ≥ n0 – không thể xảy ra

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Chú ý

• Giá trị của n0 và c không phải là duy nhất trong chứng minh công thức tiệm
cận

• Chứng minh rằng 100n + 5 = O(n2)

– 100n + 5 ≤ 100n + n = 101n ≤ 101n2 với mọi n ≥ 5

n0 = 5 và c = 101 là các hằng số cần tìm

– 100n + 5 ≤ 100n + 5n = 105n ≤ 105n2 với mọi n ≥ 1

n0 = 1 and c = 105 cũng là các hằng số cần tìm

• Chỉ cần tìm các hằng c và n0 nào đó thoả mãn bất đẳng thức trong định nghĩa
công thức tiệm cận

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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à W(g(n)) .

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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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;

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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;

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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;
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT
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;
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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;

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Mô tả thuật toán: giả ngôn ngữ

• Ví dụ. Tìm số nguyên tố lớn hơn số nguyên dương n.


• Trước hết ta xây dựng hàm kiểm tra xem một số nguyên
dương m có phải là số nguyên tố hay không (hàm Is_prime).
• Sử dụng hàm này này ta xây dựng thuật toán giải bài toán đặt
ra.
• Nếu m=a*b với 1 < a, b < m, thì một trong hai thừa số a, b sẽ
không vượt quá m . Do đó ước số nguyên tố của số nguyên
dương m bao giờ cũng không vượt quá m . Từ đó suy ra m sẽ
là số nguyên tố nếu như nó không có ước số nào trong các số
nguyên dương từ 2 đến  m  .

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Mô tả thuật toán: giả ngôn ngữ

• Thuật toán kiểm tra một số nguyên dương có phải là nguyên


tố hay không.
• Đầu vào: Số nguyên dương m.
• Đầu ra: true nếu m là số nguyên tố, false nếu ngược lại.
function Is_prime(m);
begin
i =2;
while (i*i <= m) and (m mod i ≠ 0) do i=i+1;
Is_prime = i > sqrt(m);
end Is_Prime;

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


Bình luận

• Thuật toán này chỉ có thể sử dụng đối với những số có


dưới 25 chữ số.
• Nếu áp dụng đối với những số có nhiều chữ số hơn,
chẳng hạn với

thuật toán không thể dùng được. Số n có 62 chữ số này


quả thực là số nguyên tố, và vòng lặp trên sẽ phải thực
hiện quãng 1031 lần lặp. Nếu giả thiết là một phép chia
có thể thực hiện trong thời gian 1 nanosecond thì thuật
toán sẽ chạy trong 1013 năm!

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Mô tả thuật toán: giả ngôn ngữ

• Thuật toán tìm số nguyên tố lớn hơn số nguyên dương n.


• Thuật toán sẽ sử dụng Is_prime như chương trình con.
• Đầu vào: Số nguyên dương n.
• Đầu ra: m - số nguyên tố lớn hơn n.
procedure Lagre_Prime(n);
begin
m = n+1;
while not Is_prime(m) do m=m+1;
end;
• Do tập các số nguyên tố là vô hạn, nên thuật toán Lagre_Prime
là hữu hạn.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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)).

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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í tổ
begin chức vòng lặp for thì thời gian tính của hàm
i=0; j=1; 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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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.

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Ví dụ: Tìm kiếm nhị phân (Binary Search)

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


Output: Giá trị i: 1  i  n sao cho T[i] = x.
Giả thiết là x có
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;

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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;
}
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT
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

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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;

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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)

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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, ...

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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;

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

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ó

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT


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).
Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

Questions?

Cấu trúc dữ liệu và thuật toán - N.Đ. Nghĩa. Bộ môn KHMT

You might also like