You are on page 1of 33

Chương 1: Phân tích thuật toán

1.1. Giới thiệu về phân tích thuật toán


1.2. Tính đúng đắn của thuật toán – Phương pháp Horner
1.3. Giới thiệu các chiến lược thiết kế thuật toán
1.4. Độ phức tạp của thuật toán
1.5. Giới thiệu về độ phức tạp của thuật toán
1.6. Ký hiệu tiệm cận và cách sử dụng đánh giá thuật toán
1.7. Pp phân tích thuật toán: hồi quy, phương pháp thế
1.8. Phân tích các thuật toán sắp xếp cơ bản

2/17/2023 1

Giới thiệu về phân tích thuật toán


Thuật toán (Algorithm) là một thủ tục tính toán gồm
một dãy các bước có trình tự biến đổi đầu vào (input)
thành đầu ra (output).
Thuật toán tìm ước số chung lớn nhất
Input: m, n nguyên dương.
Output: g (ước chung lớn nhất của m và n).
Bước 1: tìm r là phần dư của phép chia m cho n.
Bước 2: Nếu r = 0 thì g := n và dừng thuật toán.
Ngược lại:
m := n; n := r ;
Quay lại bước 1;
2/17/2023 2

1
Các đặc trưng của thuật toán
Input: Là các giá trị cần đưa vào (có thể là rỗng) khi
thực hiện thuật toán.
Output: là kết quả của thuật toán, có quan hệ xác định
với dữ liệu vào.
Tính xác định: Mỗi bước của thuật toán cần mô tả một
cách chính xác.
Tính khả thi: Các phép toán trong các bước của thuật
toán phải đủ đơn giản.
Tính dừng: Thuật toán phải dừng sau hữu hạn bước
ứng với mọi bộ dữ liệu thõa điều kiện đầu vào.
2/17/2023 3

Thuật toán sắp xếp


Input: một dãy số a1,a2,…,an
Output: một hoán vị của dãy đầu vào a’1,a’2,…,a’n
sao cho a’1  a’2  …  a’n
Thuật toán là đúng đắn nếu với mọi dữ liệu thỏa điều
kiện đầu vào, thuật toán dừng sau hữu hạn bước và
xuất kết quả đúng.

2/17/2023 4

2
Sắp xếp chèn
InsertionSort(A, n) {
for j = 2 to n {
▷ điều kiện: dãy A[1..j-1] được sắp

1. Tìm vị trí i trong dãy A[1..j-1] sao cho A[i] ≤ A[j] < A[i+1]
2. Chèn A[j] vào giữa A[i] và A[i+1]

▷ kết quả sau khi chèn: dãy A[1..j] được sắp


}
}
1 j

sorted
2/17/2023 5

Sắp xếp chèn


InsertionSort(A, n) {
for j = 2 to n {
key = A[j];
i = j - 1;
while (i > 0) and (A[i] > key) {
A[i+1] = A[i];
i = i – 1;
}
A[i+1] = key
}
} 1 i j

sorted Key
2/17/2023 6

3
Sắp xếp chèn
5 2 4 6 1 3

2 5 4 6 1 3

2 4 5 6 1 3

2 4 5 6 1 3

1 2 4 5 6 3

1 2 3 4 5 6 Done!
2/17/2023 7

Phương pháp Horner


Nguồn:https://en.wikipedia.org/wiki/Horner%27s_method#:~:text=Alternatively%2C%20Horner's%20method%
20also%20refers,into%20general%20use%20around%201970.

Phương pháp Horner là thuật toán đánh giá đa thức


dựa trên quy tắc Horner:

Cho đa thức p(x) như sau:

với các hệ số a0,a1,…,an là các hằng số


Bài toán: tính giá trị đa thức p(x) tại x = x0
2/17/2023 8

4
Phương pháp Horner
Biến đổi đa thức p(x):

Định nghĩa một dãy số mới như sau:

2/17/2023 9

Phương pháp Horner


Tại giá trị x = x0 ta có:

Khi đó, b0 là giá trị của biểu thức p(x0)


Điều này có nghĩa là đã xác định được giá trị của đa
thức p(x) tại điểm x = x0
2/17/2023 10

5
Phương pháp Horner
Mặt khác, khi thế ngược theo các hệ số bi, ta có:

Điều này có nghĩa là ta thực hiện phép chia đa thức


một cách dễ dàng tại điểm x = x0 , nghĩa là:

Nếu giá trị b0 = 0 (tức là phần dư bằng 0), thì x0 nghiệm


của phương trình p(x) = 0
Để tính các giá trị bi, ta bắt đầu tính từ giá trị bn = an
cho đến giá trị b0 theo công thức sau:

2/17/2023 11

Phương pháp Horner


Cho đa thức:
Với x0 = 3, ta thực hiện tính dãy số bi như sau:

Trong ví dụ trên:
a3 = 2, a2 = -6, a1 = 2, a0 = -1
b3 = 2, b2 = 0, b1 = 2, b0 = 5
Bài tập: Thực hiện phép chia đa thức
x3 – 6x2 + 11x – 6 cho x – 2
4x4 – 6x3 + 3x – 5 cho 2x – 1
2/17/2023 12

6
Các vấn đề liên quan đến thuật toán
Thiết kế thuật toán: tìm ra một thuật toán cho một bài
toán đặt ra.
Tính đúng đắn của thuật toán: thuật toán phải cho
một kết quả đúng với mọi dữ liệu vào hợp lệ.
Phân tích thuật toán: đánh giá độ phức tạp của một
thuật toán.
Tính hiệu quả:
 Thuật toán đơn giản, dễ hiểu, dễ cài đặt

 Tiết kiệm nhất tài nguyên và chạy nhanh nhất có thể:


 Dung lượng lưu trữ đầu vào, các kết quả trung gian và
đầu ra của thuật toán.
 Thời gian cần thiết để thực hiện thuật toán
2/17/2023 13

Các chiến lược thiết kế thuật toán


Cách tiếp cận theo tăng trưởng (bottom up): bắt đầu
từ trường hợp đơn giản và thực hiện cho đến khi giải
quyết được bài toán.
Ví dụ thuật toán Insertion Sort: bắt đầu từ một dãy tăng
có một phần tử, thực hiện chèn đến khi dãy được sắp.
Cách tiếp cận chia để trị (divide-and-conquer): chia
bài toán ban đầu thành các bài toán con cho đến khi
giải quyết được, sau đó tổ hợp nghiệm bài toán con để
có được nghiệm của bài toán ban đầu.
Ví dụ như Merge-Sort: chia nhỏ các dãy để sắp xếp và
trộn lại để có được dãy ban đầu tăng dần.
2/17/2023 14

7
Độ phức tạp của thuật toán
Đặc tả thuật toán cần chỉ ra các đặc điểm sau:
 Các đối tượng thuật toán cần sử dụng (đầu vào)

 Điều kiện ràng buộc (nếu có) của dữ liệu đầu vào

 Kết quả của thuật toán (đầu ra)

 Yêu cầu cho đầu ra và mối quan hệ với đầu vào

Độ phức tạp của thuật toán: là lượng thời gian và bộ


nhớ cần thiết để thực hiện thuật toán.
Khi đánh giá độ phức tạp, cần lưu ý:
 Thời gian tối thiểu để thực hiện thuật toán

 Thời gian tối đa để thực hiện thuật toán

 Thời gian trung bình khi thực hiện thuật toán

2/17/2023 15

Thời gian thực hiện của thuật toán


Có hai cách đánh giá thời gian thực hiện thuật toán:
 Phương pháp lý thuyết: cỡ dữ liệu vào.

 Phương pháp thực nghiệm:


 Các dữ liệu vào.
 Chương trình dịch.
 Tốc độ thực hiện của các phép toán của máy tính.
Bài toán tháp Hà Nội: số lần thực hiện chuyển đĩa từ cọc này
sang cọc khác (không đặt đĩa to lên đĩa nhỏ) là: F(n), ta có:
F(1) = 1;
F(n) = 2F(n-1) + 1; với n > 1
Một cách quy nạp, ta có F(n) = 2n – 1
Với n = 64 ta có F(n) = 264 – 1 lần chuyển, giả sử mỗi lần
chuyển là 1 giây, vậy ta có 5*1011 năm thực hiện.
2/17/2023 16

8
Phân tích thuật toán Insertion Sort
InsertionSort(A, n) {
for j = 2 to n {
key = A[j]
i = j - 1;
while (i > 0) and (A[i] > key) {
A[i+1] = A[i]
i = i - 1
}
A[i+1] = key
}
} Có bao nhiêu lần
dòng lệnh này được thực thi?
2/17/2023 17

Phân tích thuật toán Insertion Sort


InsertionSort(A, n) {
for j = 2 to n {
key = A[j]
i = j - 1;
while (i > 0) and (A[i] > key) {
A[i+1] = A[i]
i = i - 1
}
A[i+1] = key
}
} Có bao nhiêu lần
dòng lệnh này được thực thi?
2/17/2023 18

9
Phân tích thuật toán Insertion Sort
Statement cost time__
InsertionSort(A, n) {
for j = 2 to n { c1 n
key = A[j] c2 (n-1)
i = j - 1; c3 (n-1)
while (i > 0) and (A[i] > key) { c4 S
A[i+1] = A[i] c5 (S-(n-1))
i = i - 1 c6 (S-(n-1))
} 0
A[i+1] = key c7 (n-1)
} 0
}
S = t2 + t3 + … + tn với tj là số lần lệnh while thực
hiện tại lần lặp thứ j
2/17/2023 19

Phân tích thuật toán Insertion Sort


T(n) = c1n + c2(n-1) + c3(n-1) + c4S + c5(S - (n-1)) + c6(S - (n-1)) + c7(n-1)
= c8S + c9n + c10
 Phân tích các trường hợp:
 Trường hợp tốt nhất: bên trong vòng lặp while không bao

giờ được thực thi


 tj = 1  S = n - 1
 T(n) = an + b là một hàm tuyến tính (bậc nhất)
 Trường hợp xấu nhất: bên trong vòng lặp while được thực
thi cho tất cả các phần tử đứng trước đó
 tj = j  S = 2 + 3 + … + n = n(n+1)/2 - 1
 T(n) = an2 + bn + c là một hàm bậc hai
 Trường hợp trung bình
 Có thể giả sử rằng trong trường hợp trung bình, phần tử cần chèn
A[j] nằm giữa dãy A[1..j-1], vì vậy tj = j/2
 S ≈ n(n+1)/4
 T(n) vẫn là hàm bậc hai
2/17/2023 20

10
Các ký hiệu tiệm cận
Các ký hiệu tiệm cận để đánh giá thuật toán, gồm:
 O: Big-O

 Ω: Big-Omega

 Θ: Theta

 o: Small-o

 ω: Small-omega

Tính hiệu quả của thuật toán dựa trên:


 Thời gian

 Không gian

Cần phân tích thuật toán trong trường hợp xấu nhất
2/17/2023 21

Tiệm cận trên (Upper bound)


Định nghĩa: f(n) = O(g(n))
$ c,k > 0 ' 0 f(n)  cg(n) " n>k
 Lim f(n) / g(n) exists
n

O(g(n))={f | $ c,k>0 ' 0 f(n)  cg(n) " n>k}


“big-O của g(n) là f(n)”
Ví dụ: n = O(n2) c*g(n)
33n+17 = O(n)
n8+n7 = O(n12) f(n)
n100 = O(2n)
213 = O(1) n
k
2/17/2023 22

11
Tiệm cận trên (Upper bound)
Cho: f(n) = 3n2 + 10n + 5  O(n2)
Cần tìm các hằng số dương c and n0 sao cho:
f(n)  cn2 for all n > n0.
3n2 + 10n + 5  10n2 + 10n + 10
 10n2 + 10n2 + 10n2," n  1
 30 n2, " n  1
Nếu đặt c = 30 và n0 = 1, thì f(n)  c n2, " n ≥ n0.
Theo định nghĩa của big-O thì f(n) = O(n2).
Có thể thấy rằng:
lim n→∞ n2 / (3n2 + 10n + 5) = 1/3 > 0
2/17/2023 23

Tiệm cận trên (Upper bound)


Chứng minh rằng: n2 + 3n + lg n thuộc O(n2)
Cần tìm c và n0 sao cho
n2 + 3n + lg n <= cn2 với n > n0
Chứng minh:
n2 + 3n + lg n <= 3n2 + 3n + 3lgn với n > 1
<= 3n2 + 3n2 + 3n2
<= 9n2
Hoặc n2 + 3n + lg n <= n2 + n2 + n2 với n > 10
<= 3n2
2/17/2023 24

12
Tiệm cận dưới (Lower bound)
Định nghĩa: f(n) = W(g(n))
g(n)=O(f(n))
 Lim g(n) / f(n) exists
n

W(g(n))={f | $ c,k>0 ' 0 cg(n)  f(n) " n>k}


“Omega của g(n) là f(n)”
Ví dụ: 100n = W(n) f(n)
33n+17 = W(log n)
n8-n7 = W(n8) c*g(n)
213 = W(1/n)
n
10100 = W(1) k
2/17/2023 25

Tiệm cận dưới (Lower bound)


Chứng minh rằng: f(n) = n2 / 10 = Ω(n)
Chứng minh bằng định nghĩa:
f(n) = n2 / 10, g(n) = n
Cần tìm một số c và một số no để thỏa định nghĩa
f(n) = Ω(g(n)), nghĩa là, f(n) ≥ cg(n) với n > n0
n ≤ n2 / 10 khi n ≥ 10
Nếu c = 1 và n0 = 10, thì f(n) ≥ cn, " n ≥ n0.
Vì vậy theo định nghĩa: f(n) = Ω(n).
Dễ dàng thấy rằng:
lim n→∞ f(n)/g(n) = lim n→∞ (n/10) = ∞
2/17/2023 26

13
Tiệm cận chặt (Tight bound)
Định nghĩa: f(n) = Q(g(n))
f(n)=O(g(n)) and g(n)=O(f(n))
f(n)=O(g(n)) and f(n)=W(g(n))
Lim g(n)/f(n) and Lim f(n)/g(n) exist
n n
“Theta của g(n) là f(n)” c1g(n)

Ví dụ: 99n = Q(n) f(n)


n + log n = Q(n)
n8-n7 = Q(n8) c2g(n)
n2 + cos(n) = Q(n2)
n
213 = Q(1) k
2/17/2023 27

Tiệm cận chặt (Tight bound)


Chứng minh rằng: f(n) = 2n2 + n = Θ (n2)
Chứng minh bằng định nghĩa:
 Cần tìm ba hằng số c1, c2, và n0 sao cho:
c1n2 ≤ 2n2+n ≤ c2n2 for all n > n0
 Một nghiệm đơn giản là:
c1 = 2, c2 = 3, và n0 = 1

Ngoài ra: limn→∞(2n2+n)/n2 = 2

2/17/2023 28

14
Tiệm cận
Chứng minh rằng:
n2 + 3n + lg n thuộc Ω(n2)
Cần tìm c và n0 sao cho
n2 + 3n + lg n >= cn2 for n > n0
n2 + 3n + lg n >= n2 for n > 0
Ngoài ra:
n2 + 3n + lg n = O(n2)
và n2 + 3n + lg n = Ω (n2)
Suy ra:
n2 + 3n + lg n = Θ(n2)

2/17/2023 29

Tiệm cận yếu (Loose bound)


Định nghĩa: f(n) = o(g1(n))
f(n)=O(g1(n)) and f(n)≠W(g1(n))
“little-o của g1(n) là f(n)”
Định nghĩa: f(n) = w(g2(n))
f(n)=W(g2(n)) and f(n)≠O(g2(n))
“little-omega của g2 (n) là f(n)” g1(n)
Ví dụ: 8n = o(n log log n) f(n)
n log n = w(n)
n6 = o(n6.01) g2(n)
n2 + sin(n) = w(n)
213 = o(log n) k n
2/17/2023 30

15
So sánh các tiệm cận
c*g(n) c*f(n) c1g(n)
f(n)
f(n) g(n)
c2g(n)
n n n
k k k

f(n)  o(g(n))
0 f(n)  O(g(n))
lim f(n) / g(n) = c >0 f(n)  Θ (g(n))
n→∞
∞ f(n)  Ω(g(n))
f(n)  ω (g(n))

2/17/2023 31

Các tính chất tiệm cận


Đặt f1(n)=O(g1(n)) và f2(n)=O(g2(n))
Luật tổng: f1(n) + f2(n) = O(max(g1(n),g2(n))
Nếu mã lệnh tuần tự:
Luật tích: f1(n) • f2(n) = O(g1(n) • g2(n))
Vòng lặp lồng nhau
Luật lũy thừa: nk = O(cn) " c,k>0
Ví dụ: n1000 = O(1.001n)
2/17/2023 32

16
Các tính chất tiệm cận
Bắc cầu
f(n) = Q(g(n)) and g(n) = Q(h(n))
=> f(n) = Q(h(n))
(giữ nguyên đối với các tiệm cận o, O, w, và W)
Đối xứng
f(n) = Q(g(n)) if and only if g(n) = Q(f(n))
Đối xứng chuyển vị
f(n) = O(g(n)) if and only if g(n) = W(f(n))
f(n) = o(g(n)) if and only if g(n) = w(f(n))

2/17/2023 33

Một số công thức hữu ích


 ln n = loge n, e ≈ 2.718
 lgkn = (lg n)k
 lg lg n = lg (lg n) = lg(2)n
 lg(k) n = lg lg lg … lg n
 lg24 = ?
 lg(2)4 = ?
 Hãy so sánh lgkn vs lg(k)n?

2/17/2023 34

17
Một số công thức hữu ích
Với a > 0, b > 0, c > 0, ta có các luật sau:
• logba = logca / logcb = lg a / lg b
• logban = n logba
• log a
b b = a
• log (ab) = log a + log b
– lg (2n) = ?
• log (a/b) = log (a) – log(b)
– lg (n/2) = ?
– lg (1/n) = ?
• logba = 1 / logab
2/17/2023 35

Đánh giá tiệm cận


So sánh log2n và log10n
Theo công thức:
logab = logcb / logca
Nên:
log2n = log10n / log102 ~ 3.3 log10n
Vì vậy:
lim(log2n / log10 n) = 3.3
Suy ra:
log2n = Θ (log10n)

2/17/2023 36

18
Đánh giá tiệm cận
So sánh 2n và 3n
Vì:
lim 2n / 3n = lim(2/3)n = 0
Nên:
2n  o(3n)
3n  ω(2n)
Đối với 2n và 2n+1 thì:
2n / 2n+1 = ½,
Vì vậy:
2n = Θ (2n+1)
2/17/2023 37

Đánh giá tiệm cận


Luật L’ Hopital
lim f(n) / g(n) = lim f(n)’ / g(n)’
n→∞ n→∞

Hãy so sánh n0.5 và log n


Cần tính: lim n0.5 / log n = ?
Vì: (n0.5)’ = 0.5 n-0.5
(log n)’ = 1 / n
Nên: lim (n-0.5 / 1/n) = lim(n0.5) = ∞
Do đó: log n  o(n0.5)
Suy ra: log n  o(nε), với mọi ε > 0

2/17/2023 38

19
Đánh giá tiệm cận

log2n n nlog2n n2 n3 2n n!
10 3.3 10 33 102 103 103 106
102 6.6 102 660 104 106 1030 10158
103 10 103 104 106 109
104 13 104 105 108 1012
105 17 105 106 1010 1015
106 20 106 107 1012 1018

O is like  W is like  Q is like = Một siêu máy tính thực hiện 1 nghìn tỷ
phép toán trong 1 giây.
o is like < w is like > Điều đó sẽ mất hơn một tỷ năm.
2/17/2023 39

Đánh giá tiệm cận

2/17/2023 40

20
Công thức Stirling
Giai thừa: n!  1  2  3  . . .  (n - 2)  (n - 1)  n
n
n   1 
Định lý: n!  2 πn     1  Θ  
e   n 
với e là hằng số Euler = 2.71828…
n
Định lý: n!  2 πn   n 
e
 n   n  log2 πn 
n
Hệ quả: log (n! )  log 2 πn      n  log  
 
 O(n log n)
  e
  e 2

log(n!) = O(n log n)


2/17/2023 41

Công thức Stirling


So sánh 2n và n!
n
n! c nnn  n
lim n  lim n n  lim c n    
n  2 n  2 e n 
 2e 

Vì vậy: 2n = o(n!)

So sánh nn và n!
n! c nn n c n
lim n  lim n n  lim n  0
n  n n  n e n  e

Vì vậy: nn = ω(n!)

2/17/2023 42

21
Công thức Stirling
Đánh giá tiệm cận của log(n!)
c nnn n 1 / 2
log( n! )  log  C  log n  log( e n
)
en
1
 C  n log n  log n  n
2
n n 1
 C  log n  ( log n  n )  log n
2 2 2
 Q( n log n )
2/17/2023 43

Một số công thức

n
n3
i
i 1
2

3
 Q( n 3 )
n

1  n  Q(n)
i 1
n

i k

n k 1
 Q( n k 1 )
i 1 k 1
n
n( n  1)
i 
i 1 2
 Q( n 2 ) n

 i2 i
 ( n  1)2n 1  2  Q( n 2n )
i 1
n
r n 1  1  Q(1) ( r  1)

n
  1
 i  Q(lg n)
i
r
i 0 r  1 Q( r n ) ( r  1) i 1
n

 lg i  Q(n lg n)
i 1

2/17/2023 44

22
Một số công thức

(1  r n 1 ) /(1  r ) if r < 1


n

 r i  ( r n 1  1) /(r  1) if r > 1
i 0  n 1 if r = 1

n
2n 1  1

i 0
2  i

2 1
 2n 1  1  2n 1
n n
1 1
lim n  i  lim n  ( 1 2)i  2
i 0 2 i 0 1  12
n n
1
lim n   n    2    2   2  1  1
i 0
i
lim 1 1

i 1 2 i 0

2/17/2023 45

Một số công thức


 (a  b )   a   b
i i i i i i i

 ca  c a
n

i i 
i 1
(4i  2i )
i i
n x n

a  a  a
i m
i
i m
n
i
n
 4 i   2i  2n(n  1)  2n 1  2
i  x 1
i

i 1 i 1
n n
n 1

i 1 2 i
 n 
i 1 2 i
n

i=1..n log (i) = log 1 + log 2 + … + log n


= log 1 x 2 x 3 x … x n
= log n!
= Q(n log n)
2/17/2023 46

23
Đánh giá thuật toán
repeatedElement (A, n)
//Xác định các phần tử trong mảng có khác biệt hay không?
for i = 1 to n-1 {
for j = i+1 to n {
if (A[i] == A[j])
return true;
}
}
return false;
Cần đánh giá thuật toán trong các trường hợp:
 Tốt nhất nhất (Best case)
 Xấu nhất (Worst-case)
 Trung bình (Average case)
2/17/2023 47

Đánh giá thuật toán


Trường hợp tốt nhất:
– A[1] = A[2]
– T(n) = Θ (1)

Trường hợp xấu nhất:


– Không có phần tử lặp lại
– T(n) = (n-1) + (n-2) + … + 1 = n (n-1) / 2 = Θ (n2)

Trường hợp trung bình cần lưu ý:


– Cần giả sử việc phân bố dữ liệu
– Trong trường hợp trung bình thường liên quan đến xác xuất
2/17/2023 48

24
Đánh giá thuật toán
int Euclid(int m, int n)
{
int r;
r = m%n;
while (r != 0)  Trước lệnh while là một lệnh đơn.
{  Nếu có k lần lặp lệnh while thì số
m = n; lần kiểm tra điều kiện là (k + 1)
 Mỗi lần lặp while, cần thực hiện 3
n = r; lệnh đơn, có độ phức tạp O(1)
r = m%n;  Thời gian thực hiện thuật toán phụ
} thuộc vào số lần lệnh while.
return n;
}
2/17/2023 49

Đánh giá thuật toán


Ở lần thứ nhất, tại dòng lệnh (4): (1) int Euclid(int m, int n)
(2) {
m = n*q1 + r1, với 0 <= r1 < n (3) int r;
Tại dòng lệnh (9) (4) r = m%n;
(5) while (r != 0)
n = r1*q2 + r2, với 0 <= r2 < r1 (6) {
Nếu r1 <= n/2 thì r2 < r1<= n/2. (7) m = n;
Nếu r1 > n/2 thì q2 = 1, (8)
(9)
n = r;
r = m%n;
tức là: n = r1 + r2 (10) }
Vậy r2 < n/2 (11) return n;
(12) }
Lần lặp thứ 2: giá trị r2 < (n/2)/2
Cứ mỗi lần lặp, phần dư giảm đi một nữa và hội tụ về 0.
Giả sử lần thứ k thì phần dư r = 0, tức là n  2k.
Tức là k  log2(n)
T(n) = 1 + (k+1) + k * 3  4*log2(n) + 2  O(log2n)
2/17/2023 50

25
Đánh giá thuật toán đệ quy
Hàm đệ quy chứa lời gọi đến chính nó. Gọi F là hàm đệ
quy có thời gian chạy T(n), với n là cỡ dữ liệu đầu vào.
Bước 1: Gọi T(m) là thời gian chạy lời gọi đệ quy trong
hàm F, với m < n
Bước 2: Đánh giá thời gian chạy hàm F trên cỡ dữ liệu
nhỏ nhất n = 1. Giả sử T(1) = a, với a là một hằng số.
Bước 3: Tìm quan hệ đệ quy biểu diễn thời gian chạy
của hàm F thông qua lời gọi hàm, tức là biểu diễn T(n)
thông qua các lời gọi T(m), với m < n.
Ví dụ hàm đệ quy F chứa 2 lời gọi đệ quy, khi đó:
T(1) = a, T(n) = f(T(m1), T(m2)), với m1, m2 < n
Bước 4: Thực hiện phép thế lặp để tìm T(n)
2/17/2023 51

Đánh giá thuật toán đệ quy


Giả sử hàm đệ quy với cỡ dữ liệu vào là n chứa lời gọi
đệ quy với cỡ dữ liệu vào là n-1.
Trường hợp này dẫn đến quan hệ đệ quy dạng:
T(1) = a
T(n) = T(n-1) + g(n) với n > 1
a là một hằng số, g(n) là số phép toán sơ cấp
Sử dụng phương pháp thế lặp:
T(n) = T(n-1) + g(n) = T(n-2) + g(n-1) + g(n)
= T(n-3) + g(n-2) + g(n-1) + g(n)
....
= T(1) + g(2) + g(3) +...+ g(n)
= a + g(2) + g(3) +...+ g(n)
2/17/2023 52

26
Đánh giá thuật toán đệ quy
int Fact(int n) Thời gian thực hiện của
{ thuật toán:
T(1) = C1
int kq;
T(n) = C2 + T(n-1)
if (n <= 1) kq = 1;
Thực hiện phép thế lặp:
else kq = kq * Fact(n-1); T(2) = C2 + T(1)
return kq; T(3) = C2 + T(2)
} …
T(n-1) = C2 + T(n-2)
T(n) = C2 + T(n-1).

Bằng cánh thế liên tiếp, ta có:


T(n) = (n-1)C2 + T(1) = (n-1)C2 + C1  O(n).

2/17/2023 53

Một số trường hợp đệ quy


 T (n) = i=0..n i
T(n) = T(n-1) + n
T(0) = 0
 T(n) = i=0..n ai
T(n) = T(n-1) + an
T(0) = 1
 T(n) = aT(n-b) + f(n)
 T(n) = aT(n/b) + f(n)

2/17/2023 54

27
Một số trường hợp đệ quy
Nếu: T(n) = a • T(n/b) + f(n) với a≥1, b>1,
và đặt c = logba thì:
f(n)=O(nc-e) với một vài số e0  T(n)=Q(nc)
f(n)=Q(nc)  T(n)=Q(nc log n)
f(n)=W(nc+e) với một vài số e0
và a•f(n/b) ≤ d•f(n)
cho một vài số d<1 " n>n0  T(n)=Q(f(n))
Ví dụ: T(n) = 2T(n/2)+n  T(n)=Q(n log n)
T(n) = 9T(n/3)+n  T(n)=Q(n2)
T(n) = T(2n/3)+1  T(n)=Q(log n)
2/17/2023 55

Hệ thức truy hồi


Hệ thức truy hồi tuyến tính thuần nhất bậc k với hệ
số hằng số là hệ thức truy hồi có dạng:
an = c1an-1 + c2an-2 + ... + ckan-k
trong đó c1, c2, ..., ck là các số thực và ck ≠ 0 với
mọi k
Ví dụ: Pn = (1, 11)Pn-1 : tuyến tính thuần nhất bậc 1
fn = fn-1 + fn-2 : tuyến tính thuần nhất bậc 2
an = an-5 : tuyến tính thuần nhất bậc 5
an = an-1 + a2n-2 : không tuyến tính
Hn = 2Hn-1 + 1 : không thuần nhất
Bn = nBn-1 : không có hệ số hằng số
2/17/2023 56

28
Hệ thức truy hồi

Cho hệ thức truy hồi tuyến tính thuần nhất:


an = c1an-1 + c2an-2 + ... + ckan-k
Nghiệm của hệ thức truy hồi là: an = rn
với rn = c1rn-1 + c2rn-2 + ... + ckrn-k
Chia hai vế cho rn-k, ta có:
rk - c1rk-1 - c2rk-2 - ... - ck-1r - ck = 0

2/17/2023 57

Hệ thức truy hồi


Cho c1, c2 là các số thực.
Giả sử phương trình r2 - c1r - c2 = 0 có hai
nghiệm khác nhau là r1 và r2. Khi đó dãy {an} sẽ
là nghiệm của hệ thức truy hồi an = c1an-1 +
c2an-2 nếu và chỉ nếu:
an = 1r1n + 2r2n, với n = 1, 2, ... 1, 2 là các
hằng số
Giả sử a0 = C0, a1 = C1, tức là:
a0 = C0 = 1 + 2
a1 = C1 = 1r1 + 2r2
Giải hệ phương trình trên để tìm ra 1 , 2
2/17/2023 58

29
Hệ thức truy hồi
Tìm nghiệm của hệ thức truy hồi an = an-1 + 2an-2,
với a0 = 2 và a1 = 7.
Phương trình đặc trưng là: r2 - r - 2 = 0 có các
nghiệm là r1 = 2 và r2 = -1.
Khi đó an = 12n + 2(-1)n
a 0 = 2 = 1 + 2
a1 = 7 = 1.2 + 2.(-1)
Suy ra: 1 = 3, 2 = -1
Kết luận: nghiệm của hệ thức an = 3.2n - (-1)n
Giải hệ thức truy hồi Fibonacci
fn = fn-1 + fn-2, với f0 = 0, f1 =1
2/17/2023 59

Hệ thức truy hồi


Cho c1, c2 là các số thực và c2 ≠ 0.
Giả sử phương trình r2 - c1r - c2 = 0 có một nghiệm là r0.
Khi đó dãy {an} sẽ là nghiệm của hệ thức truy hồi
an = c1an-1 + c2an-2 nếu và chỉ nếu:
an = 1r0n + 2nr0n, với n = 1, 2,... 1, 2 là các hằng số
Giả sử a0 = C0, a1 = C1, tức là:
a0 = C0 = 1
a1 = C1 = 1r0 + 2r0
Giải hệ phương trình trên để tìm ra 1 , 2
Ví dụ: Tìm nghiệm của hệ thức truy hồi
an = 6an-1 – 9an-2, với a0 = 1, a1 = 6 (KQ: an = 3n + n3n)
2/17/2023 60

30
Bài tập
Tính độ phức tạp của đoạn chương trình sau:
int kq = 0;
for(int i = 1; I < n; i++)
{
int tam = 0;
for(int j = 1; j <= i; j++)
tam = tam + j*j;
if(i%2 == 0)
kq = kq + tam;
else
kq = kq - tam;
}
2/17/2023 61

Bài tập
Tính độ phức tạp của đoạn chương trình sau:
int kq = 0 ;
for(int i = 0; i < n; i++)
{
int tam = 0;
for(int j = i; j <= n; j++)
{
tam = tam + j*(j+1) ;
for(int k = 0; k <= j; k++)
tam = tam + k*(k-1);
}
if(i%2==0) kq = kq + tam;
else kq = kq - tam;
}
2/17/2023 62

31
Bài tập
Kiểm tra các đánh giá tiệm cận sau:
1. 2n2 + 1 = O(n2) T (also Q)
2. Sqrt(n) = O(log n) F (w)
3. log n = O(sqrt(n)) T (also o)
4. n2(1 + sqrt(n)) = O(n2 log n) F (w)
5. 3n2 + sqrt(n) = O(n2) T (also Q)
6. sqrt(n) log n = O(n) T (also o)

2/17/2023 63

Bài tập
Bài 1: Giải hệ thức truy hồi:

Bài 2: Giải hệ thức truy hồi:


an = 6an-1 – 11an-2 + 6an-3, với a0 = 2, a1 = 5, a2
= 15.
Bài 3: Giải hệ thức truy hồi:

2/17/2023 64

32
XIN TRÂN TRỌNG
CÁM ƠN!

2/17/2023 65

33

You might also like