You are on page 1of 39

CHƯƠNG 1

KỸ THUẬT
PHÂN TÍCH THUẬT TOÁN

Tuần 2 - CÁCH TÍNH ĐỘ PHỨC TẠP

1
Võ Huỳnh Trâm
Cách tính độ phức tạp

Cho 2 đoạn chương trình:


- P1 có thời gian thực hiện T1(n)=O(f1(n)).
- P2 có thời gian thực hiện T2(n)=O(f2(n)).
• Quy tắc cộng:
Thời gian thực hiện P1 và P2 nối tiếp nhau sẽ là:
T(n) = T1(n) + T2(n) = O(max(f1(n), f2(n))
• Quy tắc nhân:
Thời gian thực hiện P1 và P2 lồng nhau (chẳng hạn vòng lặp
lồng nhau) sẽ là:
T(n) = T1(n) × T2(n) = O(f1(n) × f2(n))
2
Ví dụ về quy tắc cộng và nhân

VD : P1 có T1(n) = O(n2); P2 có T2(n) = O(n3)


(+) P1 và P2 nối tiếp nhau : Quy tắc cộng
P1;
P2;
T(n) = T1(n) + T2(n) = O(max(n2, n3)) = O(n3)
(×) P1 và P2 lồng nhau : Quy tắc nhân
P1
P2 ;
T(n) = T1(n) × T2(n) = O(n2 × n3) = O (n5 )
3
Quy tắc tổng quát tính độ phức tạp

• Lệnh đọc (read, scanf), lệnh ghi (write, prinft), lệnh gán, lệnh return, định trị
biểu thức, so sánh: Thời gian = hằng số hay O(1)
• Lệnh if : if (điều kiện)
lệnh 1
else
lệnh 2;
- Thời gian = max (lệnh 1, lệnh 2) + điều kiện = max (lệnh 1, lệnh 2, điều kiện)
. Vòng lặp:
- Thời gian = Tổng thời gian thực hiện thân vòng lặp
- Vòng lặp có số lần lặp xác định (for): tính số lần lặp.
- Vòng lặp có số lần lặp không xác định (while): tính số lần lặp trong trường
hợp xấu nhất (lặp nhiều nhất). 4
Phương pháp tính độ phức tạp

• Xét phương pháp tính độ phức tạp trong 3 trường hợp:

(1) Chương trình không gọi chương trình con.


(2) Chương trình có gọi chương trình con nhưng
không đệ quy.
(3) Chương trình đệ quy.

5
Ví dụ 1.
Thủ tục sắp xếp “nổi bọt”
(1) Chương trình không gọi chương trình con.
void BubbleSort(int a[], int n)
{ int i,j,temp;
1. for(i= 0; i<=n-2; i++)
2. for(j=n - 1; j>=i+1;j--)
3. if (a[j-1] > a[j]) {
4. temp=a[j-1];
5. a[j-1] = a[j];
6. a[j] = temp;
}
} 6
Quy tắc tổng quát tính độ phức tạp

• Lệnh đọc (read, scanf), lệnh ghi (write, prinft), lệnh gán, lệnh return, định trị
biểu thức, so sánh: Thời gian = hằng số hay O(1)
• Lệnh if : if (điều kiện)
lệnh 1
else
lệnh 2;
- Thời gian = max (lệnh 1, lệnh 2) + điều kiện = max (lệnh 1, lệnh 2, điều kiện)
. Vòng lặp:
- Thời gian = Tổng thời gian thực hiện thân vòng lặp
- Vòng lặp có số lần lặp xác định (for): tính số lần lặp.
- Vòng lặp có số lần lặp không xác định (while): tính số lần lặp trong trường
hợp xấu nhất (lặp nhiều nhất). 7
Ví dụ 1.
Thủ tục sắp xếp “nổi bọt”
(1) Chương trình không gọi chương trình con.
void BubbleSort(int a[], int n)  T(n) = O(n2)
{ int i,j,temp;
1. for(i= 0; i<=n-2; i++) 1. O((n-2)-0+1)) O(n × n) = O(n2)
2. for(j=n-1; j>=i+1;j--) 2. O((n-1)-(i+1)+1)) O(n × 1) = O(n)
3. if (a[j-1] > a[j]) { 3. O(1)  O(max(1, 1)) = O(1)
4. temp = a[j-1]; 4. O(1)
5. a[j-1]= a[j]; 5. O(1)  O(max(1, 1, 1)) = O(1)
6. a[j] = temp; 6. O(1)
}
} 8
Ví dụ 1.
Thủ tục sắp xếp “nổi bọt”

void BubbleSort(int a[], int n)


{ int i,j,temp;
1. for(i= 0; i<=n-2; i++) 1. O((n-2) - 0 + 1)) = O (n-1) = O(n)
2. for(j=n-1; j>=i+1;j--) 2. O((n-1) - (i+1) + 1)) = O(n-i-1) = O(n)
3. if (a[j-1] > a[j]) {
4. temp = a[j-1];
Số số hạng = (Số cuối – số đầu) + 1
5. a[i] = a[j];
6. a[j] = temp;
}
}
9
Tính độ phức tạp của thủ tục
sắp xếp “nổi bọt”

• Chương trình sử dụng các vòng lặp xác định. Toàn bộ chương trình chỉ gồm
một lệnh lặp {1}, lồng trong lệnh {1} là lệnh lặp {2}, lồng trong lệnh {2} là
lệnh {3} và lồng trong lệnh {3} là 3 lệnh nối tiếp nhau {4}, {5} và {6}.
• 3 lệnh gán {4}, {5} và {6} đều tốn O(1) thời gian, việc so sánh a[j-1] > a[j]
cũng tốn O(1) thời gian, do đó lệnh {3} tốn O(1) thời gian.
• Vòng lặp {2} thực hiện (n-i-1) lần, mỗi lần O(1) do đó vòng lặp {2} tốn
O((n-i-1)×1) = O(n-i-1).
• Vòng lặp {1} có i chạy từ 0 đến n-2 nên thời gian thực hiện của vòng lặp
{1} cũng là độ phức tạp của thuật toán:
n 2
n(n 1)
T(n)  (n  i -1)   O(n2 )
i0 2
10
Ví dụ 2.
Thủ tục tìm kiếm tuần tự
(1) Chương trình không gọi chương trình con.
1. int tim_kiem (int x, int a[ ], int n)) {
2. int found, i;
3. found = 0;
4. i = 0;
5. while (i < n  ! found)
6. if (a[i] == x)
7. found = 1;
8. else
9. i = i + 1;
10. return i;
11
11. }
Ví dụ 2.
Thủ tục tìm kiếm tuần tự
(1) Chương trình không gọi chương trình con.
1. int tim_kiem (int x, int a[ ], int n)) {  T(n) = O(n)
2. int found, i;
3. found = 0; 3. O(1)
4. i = 0; 4. O(1)
5. while (i < n  ! found) 5. O(n)  O(n × 1) = O(n)
6. if (a[i] == x) 6. O(1)  O(max(1, 1, 1)) = O(1)
7. found = 1; 7. O(1)
8. else
9. i = i + 1; 9. O(1)
10. return i; 10. O(1) O(max(1, 1, n, 1))=O(n)
12
11. }
Tính độ phức tạp
của hàm tìm kiếm tuần tự
• Các lệnh {3}, {4}, {5} và {10} nối tiếp nhau, do đó độ phức
tạp của hàm Search là độ phức tạp lớn nhất trong 4 lệnh này.
• 3 lệnh {3}, {4} và {10} đều có độ phức tạp O(1), do đó độ
phức tạp lớn nhất trong 4 lệnh này là độ phức tạp của lệnh {5}.
Lồng trong lệnh {5} là lệnh {6}, lệnh {6} có độ phức tạp O(1).
• Lệnh {5} là một vòng lặp không xác định, do đó cần tính số lần
lặp trong trường hợp xấu nhất (khi tất cả các phần tử của mảng
a đều khác x): xét tất cả các a[i], i có các giá trị từ 0 đến (n – 1)
hay vòng lặp {3} thực hiện n lần, tốn O(n) thời gian.
Vậy T(n) = O(n)
13
Bài tập

14
Bài giải – Bài tập 1a).

1. a) Tính tổng của các số


1. sum := 0;  1. O(1)  O(max(1, n) = O(n)
2. for i:=1 to n do begin  2. O(n)  O(n × 1) = O(n)
3. readln (x);  3. O(1)
 O(max(1, 1) = O(1)
4. sum := sum + x;  4. O(1)
end;

 T(n) = O(n)
15
Bài giải – Bài tập 1b).

1. b) Tính tích 2 ma trận vuông cấp n

1. for i:=1 to n do  1. O(n)  O(n3)


2. for j:=1 to n do begin  2. O(n)
 O(n2)
3. c[i, j] := 0;  3. O(1)
 O(n)
4. for k:=1 to n do  4. O(n)
 O(n)
5. c[i, j]:=c[i,j]+a[i,k]*b[k,j];  5. O(1)
end;
 T(n) = O(n3) 16
Phương pháp tính độ phức tạp

• Xét phương pháp tính độ phức tạp trong 3 trường hợp:

(1) Chương trình không gọi chương trình con.


(2) Chương trình có gọi chương trình con
không đệ quy.
(3) Chương trình đệ quy.

17
Ðộ phức tạp của chương trình có gọi chương trình con
không đệ qui

A B B1 B11

C B2 B12

18
Ví dụ 3.
Sắp xếp “nổi bọt” gọi chương trình con
(2) Chương trình có gọi chương trình con không đệ quy
1. void Swap (int &a,int &b) { O(1)
2. int temp;
3. temp = x;
4. x = y;
5. y = temp; }

6. void BubbleSort(int a[],int n) {


7. for(i= 0; i<=n-2; i++) O(n)  O(n2)
8. for(j=n - 1; j>=i+1;j--) O(n)
9. if (a[j-1] > a[j]) { O(1)  O(n )
10. Swap(a[j-1],a[j]); } O(1)  O(1)
19
Tính độ phức tạp của sắp xếp “nổi bọt” có gọi
chương trình con

• Chương trình BubbleSort gọi chương trình con Swap, do đó để tính độ phức
tạp của BubbleSort trước tiên cần tính độ phức tạp của Swap.
• Swap bao gồm 3 lệnh gán 3 lệnh gán {3}, {4} và {5} đều tốn O(1), do đó độ
phức tạp của Swap là O(1).
• Trong BubbleSort: lệnh {10} gọi Swap nên tốn O(1); lệnh {9} có điều kiện so
sánh a[j] < a[j-1] cũng tốn O(1); vòng lặp {8} thực hiện (n – i - 1) lần, mỗi lần
tốn O(1) nên vòng lặp {8} tốn O((n-i- 1) ×1) = O(n-i-1); Vòng lặp {7} có i
chạy từ 0 đến n-1 nên thời gian thực hiện của vòng lặp {7} cũng là độ phức tạp
của thuật toán:
n 2
n(n 1)
T(n)  (n  i - 1)   O(n2 )
i 0 2 20
Phương pháp tính độ phức tạp

• Xét phương pháp tính độ phức tạp trong 3 trường hợp:

(1) Chương trình không gọi chương trình con.


(2) Chương trình có gọi chương trình con
không đệ quy.
(3) Chương trình đệ quy.

21
Phân tích
các chương trình đệ qui
• 2 dạng chương trình đệ quy:
A
A B

Đệ quy trực tiếp Đệ quy gián tiếp

• Tính độ phức tạp chương trình đệ quy:


(1) Thành lập phương trình đệ quy T(n)
(2) Giải phương trình đệ quy tìm nghiệm
 Suy ra tỷ suất tăng f(n) hay O(f(n).
22
Chương trình đệ quy

• Chương trình đệ quy giải bài toán kích thước n, phải có ít nhất một
trường hợp dừng ứng với một n cụ thể và lời gọi đệ quy giải bài
toán kích thước k (k<n)
• Ví dụ : Chương trình đệ quy tính n!

• Trường hợp dừng n = 0 và lời gọi đệ quy k = n-1. 23


Thành lập phương trình đệ quy

• Phương trình đệ quy là phương trình biểu diễn mối liên hệ giữa T(n) và T(k),
trong đó T(n) và T(k) là thời gian thực hiện chương trình có kích thước dữ liệu
nhập tương ứng là n và k, với k < n.
• Ðể thành lập được phương trình đệ quy, phải căn cứ vào chương trình đệ quy.
- Khi đệ quy dừng: xem xét khi đó chương trình làm gì và tốn hết bao nhiêu
thời gian (thông thường thời gian này là hằng số C(n))
- Khi đệ quy chưa dừng: xem xét có bao nhiêu lời gọi đệ quy với kích thước
k thì sẽ có bấy nhiêu T(k).
• Ngoài ra, còn phải xem xét thời gian phân chia bài toán và tổng hợp các lời giải
(chẳng hạn gọi thời gian này là d(n)).

24
Dạng phương trình đệ quy

Dạng tổng quát của một phương trình đệ quy là:

C(n)  Khi đệ quy dừng


T(n)  
F(T(k)) d(n)  Khi đệ quy chưa dừng

• C(n): thời gian thực hiện chương trình ứng với trường hợp đệ quy dừng.
• F(T(k)): hàm xác định thời gian theo T(k).
• d(n): thời gian phân chia bài toán và tổng hợp các kết quả.

25
Phương trình đệ quy

TG thực
hiện khi đệ
C(n) quy dừng
T(n)  
F(T(k))  d(n) TG phân chia
BT và tổng
hợp kết quả
TG thực hiện MQH: bao TG thực hiện
BT cha T(n) nhiêu lời gọi
BT con T(k)
26
Ví dụ 1. Phương trình đệ quy của n!
n! = n*(n-1)*(n-2)*… *2*1

• Gọi T(n) là thời gian tính n!.


• Thì T(n-1) là thời gian tính (n-1)!.
• Trường hợp n = 0 : thực hiện return 1
tốn O(1)  T(0) = C1.
• Trường hợp n > 0: gọi đệ quy giai_thua(n-1),
tốn T(n-1)  T(n) = T(n -1).
• Sau khi có kết quả của việc gọi đệ quy, chương trình phải
nhân kết quả đó với n và trả về tích số. Thời gian thực hiện
phép nhân và trả kết quả về là một hằng C2.

• Vậy ta có phương trình đệ quy như sau:


27
Ví dụ 2. Phương trình đệ quy của
thuật toán MergeSort

• Hàm MergeSort nhận danh sách có độ dài n và trả về danh sách được sắp xếp.
• Thủ tục Merge nhận 2 danh sách đã được sắp thứ tự L1 và L2, mỗi danh sách có độ
dài n/2, trộn chúng lại với nhau để được một danh sách gồm n phần tử có thứ tự.
28
Mô hình minh hoạ Mergesort

• Sắp xếp danh sách L


gồm 7 phần tử :
38, 27, 43, 3, 9, 82, 10
Ví dụ 2. Phương trình đệ quy của
thuật toán MergeSort
• T(n): mergeSort (n phần tử)
T(n/2): mergeSort (n/2 phần tử).
• Khi n = 1: return(L) T(n) = C1.
• Khi n > 1: gọi đệ quy mergeSort
2 lần cho 2 danh sách con với độ dài
n/2  T(n) = 2T(n/2).
• Ngoài ra, thời gian chia danh sách và
trộn hai danh sách kết quả (hàm merge):
cần thời gian O(n) = nC2.
• Vậy ta có phương trình đệ quy như sau:

30
Ví dụ 3. Phương trình đệ quy của
Thủ tục tháp Hà nội số tầng n
void ThapHN(int n, char A, char B, char C)
{ if(n > 1)
{
ThapHN(n-1,A, C, B);
printf("Chuyen tu %c sang %c\n", A, C);
ThapHN(n-1,B, A, C);
}
}

C1 n 1
Phương trình đệ quy : T(n)  
2T(n -1)  C2 n  1
31
Ví dụ 4. Phương trình đệ quy của
thuật toán tìm kiếm nhị phân dãy n có thứ tự

int binarysearch(int x, int *a, int left, int right)


{
if(left > right) return -1;
int mid = (left + right)/2;
if(x == a[mid]) return mid;
if (x < a[mid]) return binarysearch(x,a,left,mid-1);
else return binarysearch(x,a,mid+1,right);
}

1 n 1
Phương trình đệ quy : T(n)  
T(n/2)  1 n 1 32
Ví dụ 4. Phương trình đệ quy của
thuật toán tìm kiếm nhị phân dãy n thứ tự

33
Giải phương trình đệ quy

• Có 3 phương pháp giải phương trình đệ quy:


(1) Phương pháp truy hồi.
- Triển khai T(n) theo T(n-1), rồi T(n-2), … cho đến T(1) hoặc T(0)
- Suy ra nghiệm
(2) Phương pháp đoán nghiệm.
- Dự đoán nghiệm f(n)
- Áp dụng định nghĩa tỷ suất tăng và chứng minh f(n) là tỷ suất tăng
của T(n)
(3) Phương pháp lời giải tổng quát.
34
Phương pháp truy hồi

• Dùng đệ quy để thay thế T(m) với m < n (vào phía phải phương trình)
cho đến khi tất cả T(m) với m>1 được thay thế bởi biểu thức của T(1)
hoặc T(0).

• Vì T(1) và T(0) là hằng số nên công thức T(n) chứa các số hạng chỉ
liên quan đến n và hằng số.
• Từ công thức đó suy ra nghiệm của phương trình.
35
Ví dụ 1. Giải PTĐQ bằng PP truy hồi (n!)

Hàm tính Giai thừa n!

Ta có : T(n) = T(n-1) + C2 (1)


= [T((n-1)-1) + C2] + C2 = T(n-2) + 2C2 (2)
Quy luật truy hồi
= [T((n-2)-1) + C2] + 2C2 = T(n-3) + 3C2 (3)
…… = T(0) = C1
T(n) = T(n-i) + iC2 (i)
• Quá trình truy hồi kết thúc khi n - i = 0 hay i = n
 T(n) = T(0) + nC2 = C1 + nC2 = O(max(1, n)) = O(n)
Ví dụ 2. Giải PTĐQ bằng PP truy hồi (MergeSort)

Hàm MergeSort
T(n/2)=2T((n/2)/2)+(n/2)C2

• T(n) = 2T(n/2) + nC2 (1)


= 2[2T(n/4) + (n/2)C2] + nC2 =4T(n/4) + 2nC2 (2)
= 4[2T(n/8 ) + (n/4)C2] + 2nC2 =8T(n/8) + 3nC2 (3)
Quy luật = ........
= T(n/2i )= T(1) = C1
truy hồi
= 2i T(n/2i ) + inC2 (i)
Quá trình truy hồi kết thúc khi n/2i = 1 hay 2i = n  i = logn
 T(n) = nT(1) + logn.nC2 = nC1 + nlognC2 =O(max(n, nlogn)) = O(nlogn)
37
Bài tập

Giải các phương trình đệ quy sau với T(1) = 1 và:

1. T(n) = T(n/2) + 1

2. T(n) = 3T(n/2) + n

3. T(n) = 4T(n/2) + n2

38
Một số công thức Logarit

39

You might also like