You are on page 1of 69

Phong cách lập trình tốt &

Phân tích giải thuật

Giảng viên: Văn Thiên Hoàng


Đại học Kỹ Thuật Công Nghệ TP. HCM
Mục tiêu
 Cung cấp những quy định cơ bản trong lập trình
nhằm có được phong cách lập trình tốt.
 Biết được một số kỹ thuật tinh chỉ mã nguồn
 Biết cách phân tích độ phức tạp một giải thuật và
chọn giải thuật phù hợp.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 2


Nội dung
 Giới thiệu
 Phong cách viết mã nguồn
 Tối ưu sự thực thi mã nguồn
 Phân tích độ phức tạp giải thuật

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 3


Giới thiệu
 Một chương trình tốt:
- Cấu trúc dữ liệu + giải thuật phù hợp

- Phong cách và kỹ thuật mã hóa

-Tên biến đã khai báo là gì?


-Kiểu dữ liệu gì?
-Toàn cục hay cục bộ?
Vài chục nghìn
dòng lệnh
-Con số này có nghĩa gì?
-Tên này có phải hằng số
không?
-Hàm này có chức năng gì?
-Hàm có chức năng này nằm
ở dòng code thứ mấy? …

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 4


Cách đặt tên cho Biến, Hàm
 Chọn một cách đặt tên nhất quán cho các định danh
 Một số quy tắc cần quan tâm như sau:
- Tên định danh phải thể hiện được ý nghĩa
 Biến lặp: i, j, k
 Biến dùng làm tọa độ: x, y, z, ..
 Biến lưu dữ liệu nên đặt gợi nhớ: hoTen, tuoi, tu, mau, ..
- Tên phải xác định được kiểu dữ liệu lưu trữ.
 Ví dụ: biến đểm kiểu số nguyên: iCount
 Biến lưu nội dụng kiểu chuỗi: strContent

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 5


Cách đặt tên cho Biến, Hàm
 Cú pháp Hungary
- Thêm các tiền tố chứa kiểu dữ liệu dữ liệu vào tên biến.
Tiền tố Kiểu dữ liệu Minh họa
B boolean bool bStop
c char char cLetterGenre
str/s C++ string string strFirstName
si short integer short siTables
i/n integer int iCars
int nCars
li long integer long liStars
f floating point float fPercent

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 6


Cách đặt tên cho Biến, Hàm
 Hằng số: tất cả các ký tự đều viết hoa
 #define MAXSIZE 100
 const int MAXLENGTH 200
 Cách đặt tên hàm: Hàm nên bắt đầu bằng động từ,
các từ được viết hoa ký tự đầu.
- CString GetName(); //VC++ standard
- String setName(); //Sun Java
standard

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 7


Canh lề
 Sử dụng tab để canh lề  Chương trình có cấu trúc
rõ ràng.
for (i = 0;i < N; i++) for (i = 0; i < N; i++)
{ {
if (Check(i)) { if (Check(i)){
Action1(); Action1();
Action2();
Action2();
}else
}else
Action3(); ActionMain();
Action3();
}
ActionMain();
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 8


Dùng khoảng trắng
 Sử dụng khoảng trắng để chương trình dễ nhìn
hơn.

int count; int count;


for(count=0;count<10;count++) for (count = 0; count < 10; count++)
{ {
printf(“%d”,count*count+count); printf(“%d”, count * count + count);
} }

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 9


Tránh nhiều dòng lệnh
 Tránh nhiều dòng lệnh trên một dòng.

if(a>5){ b=a;a++; } if (a > 5)


{
b=a;
a++;
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 10


Định nghĩa Hằng
 Sử dụng định nghĩa hằng nhằm tránh nhữn con số
khó hiểu (magic number).
… #define MAX_LEN 100
for(int i=0; i < 100; i ++) #define MAX_NUM 100
A[i] = Rand(100); …
… for(int i=0; i < MAX_LEN; i++)
k = InputNum(); A[i] = Rand(MAX_NUM);
j=0; …
while (A[j] != k && j < 100) k = InputNum();
j++; j=0;
… while (A[j] != k && j < MAX_LEN)
j++;

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 11


Chú thích
 Biến, hàm nên được viết chú thích ý nghĩa và chức
năng rõ ràng. Đoạn chương trình phức tạp cũng
nên giải thích ý nghĩa.
int CheckFactor(int n)
{
/* Ý nghĩa: kiểm tra xem 1 số có phải là nguyên tố hay không
Tham số vào: n số cần kiểm tra
Tham số ra: giá trị trả về
0: không phải số nguyên tố
1: là số nguyên tố
/**/
….
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 12


Chú thích
 Ví dụ: chú thích cho biến ảnh

byte Image[]; // buffer ảnh


int Rows, Cols; // số dòng, số cột
int r, c; // dòng cột hiện hành
int PixelCount; // tổng số pixel

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 13


Biểu thức điều kiện
 Nên viết biểu thức điều kiện mang tính tự nhiên,
không nên viết dạng phủ định.

if ( !(iBlock < Block1 ) || !(iBlock >= Block2))


{…}

if ( (iBlock >= Block1 ) || (iBlock < Block2))


{…}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 14


Dùng ngôn ngữ
 Dùng chính ngôn ngữ đó để tính kích thước đối
tượng.

//cấp phát bộ nhớ cho mảng n phần tử



a=(int*) malloc(4*n) //giả sử kiểu int 4 bytes

//cấp phát bộ nhớ cho mảng n phần tử

a=(int*) malloc(sizeof(int)*n)

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 15


Bài tập
 Viết chương trình nhập vào n<100 số nguyên
dương ngẫu nhiên trong đoạn [0,100]. In ra hình các
số nguyên tố.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 16


Bài tập
#include <stdio.h>
#include <stdlib.h>
#define N 100 //gia tri toi da cua so nguyen
#define MAX 100 //kich thuoc toi da cua mang
void nhapMang(int iArr[], int &n){
printf(“nhap vao so phan tu:”);
scanf(“%d”, &n);
randomize();
for (int i = 0; i < n ; i++)
iArr[i]=random(100);
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 17


Bài tập
//kiem tra so nguyen to
//=1: la so nguyen to, =0: khong la nguyen to
int laNguyenTo(int n){
If (n<2) return 0;
for(int i=2;i<=n/2;i++)
If (n%2==0) return 0;
return 1;
}
//hien thi so nguyen to trong mang iArr
void hienThiSNT(int iArr[], int n){
for (int i=0;i<n;i++)
if (laNguyenTo(iArr[i])) printf(“%4d”,iArr[i]);
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 18


Bài tập
//chuong trinh chinh
//nhap mang
//hien thi cac so nguyen to trong mang
void main(){
int iArr[MAX]; //mang luu cac so nguyen
int n; //so phan tu
nhapMang(iArr, n);
hienThiSNT(iArr, n);
getch();
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 19


Tối ưu hóa thực thi mã nguồn
 Một chương trình hiệu qủa
- Biên dịch nhanh (công sức lập trình)
- Yếu tố thời gian: NHANH (góc nhìn của user)

- Yếu tố lưu trữ: NHỎ (yếu tố không gian)

- Khó đạt được cả ba

 Dùng các cấu trúc dữ liệu hợp lý, cải tiến giải thuật,
sử dụng các phát biểu hợp lý cũng giúp làm tăng
đáng kể về hiệu suất thời gian chạy của chương
trình

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 20


Tối ưu hóa thực thi mã nguồn
 Hai yếu tố thời gian và không gian mâu thuẫn nhau
 Muốn chạy nhanh thì chấp nhận kích thước
chương trình lớn.
 Ngày nay, với sự tiến bộ của kỹ thuật, CPU tốc độ
cao, bộ nhớ lớn, khuynh hướng hiện nay là chấp
nhận dư thừa dữ liệu để đạt yêu cầu về thời gian.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 21


Ví dụ
 Khai báo cấu trúc về đoạn thẳng
struct Line
{
int x1,y1; // điểm đầu
int x2,y2; // điểm cuối
};
double getLen (Line L) // hàm tính độ dài
{
return sqrt((L.y2-L.y1)*(L.y2-L.y1) + (L.x2-L.x1)*(L.x2-L.x1));
}
 Mỗi lần truy xuất độ dài 1 đoạn thẳng, 8 lần truy
xuất dữ liệu (biến), 4 phép trừ, 2 phép nhân, một
phép cộng và 1 lời gọi hàm sqrt được thực thi

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 22


Cải tiến
struct Line
{ int x1,y1; // điểm đầu
int x2,y2; // điểm cuối
double len ; // độ dài
};
Chỉ phải cập nhật trị của len mỗi lần khi x1,y1,x2,y2
thay đổi, còn khi truy xuất độ dài chỉ tốn 1 lần truy
xuất bộ dữ liệu (biến).

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 23


Một số kỹ thuật tinh chỉnh code
 Thu gọn những biểu thức dùng nhiều lần.
 Đưa những biểu thức không phụ thuộc vòng lặp ra ngoài
 Thay thế một biểu thức bằng biểu thức tương đương
nhưng lợi về thực thi.
 Loại bỏ câu lệnh rẽ nhánh trong vòng lặp
 Tinh chỉnh vòng lặp
 Thoát khỏi vòng lặp sớm nhất
 Cải tiến tính toán cho biến cờ
 Khai báo biến cục bộ trong phạm vi gần nhất
 Giảm số lượng tham số truyền vào hàm
 Một số kỹ thuật khác

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 24


Biểu thức hằng và vòng lặp
Ví dụ:
for(i =0; i < strlen(str); i++)
….

int n = strlen(str)
for(i =0; i < n; i++)
….

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 25


Thay thế biểu thức tương đương
Ví dụ: khi so sánh khoảng cách của hai điểm ta
thường làm như sau

if (sqrt(dx1*dx1+dy1*dy1) < sqrt(dx2*dx2+dy2*dy2))


if ((dx1*dx1+dy1*dy1) < (dx2*dx2+dy2*dy2))


...

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 26


Câu lệnh rẽ nhánh & vòng lặp
 Ví dụ
Chương trình A Chương trình B
#define MAX 1000 #define MAX 1000
… if (w) then
for i to MAX do for i to MAX do
{ {
x[i] = x[i] + y[i]; x[i] = x[i] + y[i];
if (w) then y[i] = 0; y[i] = 0;
} }
else
for i to MAX do
x[i] = x[i] + y[i];

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 27


Tinh chỉ vòng lặp
 Dùng vòng lặp giảm
 Lợi dụng khả năng kiểm tra số khác không hiệu quả

hơn các kiểm tra khác ở tại 1 số máy.


for (i=0; i<N; i++) a[i]=0;
for (i=N-1; i=0; i--) a[i]=0;
 Gom vòng lặp

for (i=0;i<n; i++) a[i]= 0;


for (i=0;i<n; i++) b[i]= 0;
for (i=0;i<n; i++) a[i]= b[i]= 0;

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 28


Thoát khỏi vòng lặp sớm nhất
 Ví dụ
Chương trình A Chương trình B
#define MAX 10000 #define MAX 10000
… …
num= -99; num= -99;
found = FALSE; found = FALSE;
for(i=0;i<MAX;i++) for(i=0; i<MAX; i++)
{ {
if( list[i] == num ) if( list[i] == num )
{ {
found = TRUE; found = TRUE;
} break;
} }
if( found ) }
printf(“There is %d.“, num); if( found ) printf(“There is %d.“, num);

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 29


Cải tiến tính toán cho biến cờ
Ví dụ:
if (x >y)
flag =1;
else
flag =0;

Cải tiến thành:


flag = x>y;

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 30


Sử dụng macro
 Ví dụ:
int max(int a, int b)
{
return a>b? a: b;
}

 Chuyển thành macro:


#define max(a, b) ((a)>(b)) ? (a) : (b)

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 31


Giảm số lượng truyền tham số
 Ví dụ :
void Print(struct Student s)
{
printf(“%d”, s.StudentCode);

}
 Thay bằng:
void Print(const struct Student *s)
{
printf(“%d”, s->StudentCode);

}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 32


Một sô kỹ thuật khác
 Loại bỏ việc kiểm tra zero

if( x=0)  if (x)

if (x==0)  if (!x)

if (pointer !=NULL)  if (pointer)

if (ch =‘\0’)  if (ch)

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 33


Một sô kỹ thuật khác
 Ưu tiên đặt thành phần thường truy xuất ở đầu cấu
trúc

struct Item

Item* Next; // field thường truy xuất

<data-type> data;

};

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 34


Một sô kỹ thuật khác
 Tránh bớt việc ép kiểu vì tốn chi phí.
 Chỉ nên dùng kiểu int, double để tránh việc ép kiểu
không cần thiết ( char -> int, short -> int, float ->
double)
 Tránh dùng kiểu unsigned để bớt chi phí nhận dạng
kiểu lưu trữ.
 Tránh dùng kiểu bit-field vì tác vụ trích bit có chi phí
cao.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 35


Phân tích độ phức tạp của giải thuật
 Sự cần thiết phân tích giải thuật

GT A GT C

GT B GT tốt

Vấn đề cần giải quyết

1. Giải thuật đúng


2. Giải thuật đơn giản
3. Giải thuật thực hiện nhanh

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 36


Hai cách phân tích
 Thời gian tính toán của một giải thuật thường là một
hàm của kích thước dữ liệu nhập.
 Chúng ta quan tâm đến:
- Trường hợp trung bình (average case): thời gian tính
toán mà một giải thuật cần đối với một “dữ liệu nhâp
thông thường” (typical input data).
- Trường hợp xấu nhất (worst case): thời gian tính toán
mà một giải thuật cần đối với một “dữ liệu nhâp xấu
nhất”

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 37


Biểu đồ đánh giá
 Biểu đồ thể hiện các trường hợp đánh giá thời gian
thực hiện
Xấu nhất

6n Trung bình
Thời gian thực hiện

5n
Tốt nhất
4n

3n

2n

1n

1 2 3 4 5 6 7 8 9 10 11 12 …..
Kích thước dữ liệu đầu vào

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 38


Cách phân tích
 Bước 1: Đặc trưng hóa dữ liệu đầu vào và quyết định
kiểu phân tích thích hợp.
- Chứng minh rằng thời gian tính toán luôn nhỏ hơn một “cận
trên” (upper bound), hay
- Dẫn xuất ra thời gian chạy trung bình đối với một dữ liệu nhập
ngẫu nhiên.
 Bước 2: Nhận dạng thao tác trừu tượng (abstract
operation) mà giải thuật dựa vào đó làm việc.
- Ví dụ: lệnh gán, đọc ghi dữ liệu, thao tác so sánh trong giải thuật
sắp thứ tự.
 Bước 3: Thực hiện phân tích toán học để tìm ra các giá
trị trung bình và giá trị xấu nhất của các đại lượng quan
trọng.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 39


Phân lớp độ phức tạp
 Hầu hết các giải thuật thường có một thông số
chính, n, số mẩu dữ liệu nhập mà được xử lý.
Ví dụ:
- Kích thước của mảng (array) được sắp thứ tự hoặc tìm
kiếm.
- Số nút của một đồ thị.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 40


Phân lớp độ phức tạp
 Các độ phức tạp thường gặp:
- 1, Log2n, n, nlog2n, n2, n3, 2n, n!, nn
 Thông thường thuật giải có độ phức tạp đa thức thì
có thể cài đặt
 Còn phức tạp ở mức hàm mũ thì phải cải tiến giải
thuật!

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 41


Hàm tăng trưởng
1,00E+10

1,00E+09

1,00E+08 n
log n
1,00E+07
sqrt n
n log n
1,00E+06
100n
n^2
1,00E+05
n^3
T(n)

1,00E+04

1,00E+03

1,00E+02

1,00E+01

1,00E+00

1,00E-01
2 4 8 16 32 64 128 256 512 1024
n

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 42


Hàm tăng trưởng
1,00E+155

1,00E+143

1,00E+131

1,00E+119 n
log n
1,00E+107
sqrt n
1,00E+95 n log n
100n
1,00E+83 n^2
T(n)

n^3
1,00E+71
2^n
1,00E+59

1,00E+47

1,00E+35

1,00E+23

1,00E+11

1,00E-01
2 4 8 16 32 64 128 256 512 1024
n

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 43


Hàm chặn trên
 Cho hàm f(n), f(n) bị chặn trên bởi g(n) nếu tồn tại các hằng c,
n0 sao cho:
- f(n) ≤ cg(n) với mọi n ≥ n0 (tức là f(n) có tỉ suất tăng là g(n) và
ký hiệu f(n) là O(g(n))
- Lưu ý: O(cf(n)) = O(f(n))
với c là hằng số, O(c) = O(1).
 Thường dùng đánh giá độ phức tạp c ⋅ g( n)
tính toán giải thuật trong trường hợp f (n )

Running Time
tồi tệ nhất (chặn trên của hàm thời
gian)

n0 Input Size

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 44


Hàm chặn trên
4g(n)=4n2
4 g(n) = 4n2
= 3n2 + n2
≥ 3n2 + 9 for all n ≥ 3 f(n)=3n2+5
> 3n2 + 5
= f(n)
Thus, f(n)=O(g(n)).
g(n)=n2

3
Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 45
Hàm chặn dưới
 Cho hàm f(n), f(n) bị chặn dưới bởi g(n) nếu tồn tại các hằng
c, n0 sao cho:
- cg(n) ≤ f(n) với mọi n ≥ n0 (tức là f(n) có tỉ suất tăng là g(n) và
ký hiệu f(n) là Ω (g(n))
- Lưu ý: O(cf(n)) = O(f(n))
với c là hằng số, O(c) = O(1). f (n )
Thường dùng để biểu diễn cg(n)

Running Time

trường hợp tốt nhất của giải


thuật (cận dưới).

n0 Input Size

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 46


Hàm chặn dưới

g(n)/4 = n2/4
= n2/2 – n2/4
≤ n2/2 – 9 for all n ≥ 6 f(n)=n2/2-7
< n2/2 – 7
Thus, f(n)= Ω (g(n)).

c g(n)=n2/4

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 47


Ký hiệu O
 Ký hiệu O là một cách hữu ích để phát biểu cận trên
về thời gian tính toán mà độc lập đối với đặc tính dữ
liệu nhập và chi tiết hiện thực hóa.
 Chúng ta cố gắng tìm cả “cận trên” lẫn “cận dưới”
của thời gian tính toán trong phân tích trường hợp
xấu nhất.
 Nhưng cận dưới (lower-bound ) thì thường khó xác
định.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 48


Phân tích trường hợp trung bình
 Với kiểu phân tích này, ta phải
- Đặc trưng hóa dữ liệu nhập của giải thuật
- Tính giá trị trung bình của số lần một phát biểu được
thực thi.
- Tính thời gian tính toán trung bình của toàn giải thuật.
 Nhưng thường thì khó
- Xác định thời gian chạy của mỗi phát biểu.
- Đặc trưng hóa chính xác dữ liệu nhập trong thực tế.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 49


Các kết quả tiệm cận và xấp xỉ
 Kết quả của một sự phân tích toán học thường mang
tính xấp xỉ (approximate): nó có thể là một biểu thức
gồm một chuỗi những số hạng giảm dần tầm quan
trọng.
 Ta thường để ý đến các số hạng dẫn đầu trong biểu
thức toán học.
 Ví dụ: Thời gian tính toán trung bình của một chương
trình là:
a0nlgn + a1n + a2
 Ta có thể viết lại là:

a0nlgn + O(n)
Với n lớn, ta không cần tìm giá trị của a1 hay a2.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 50


Các kết quả xấp xỉ
 Ký hiệu O cho ta một cách tìm ra kết quả xấp xỉ khi
N lớn.
 Do đó, thông thường chúng ta có thể bỏ qua một số
đại lượng khi có tồn tại một số hạng dẫn đầu trong
biểu thức.
 Ví dụ: nếu biểu thức là N(N-1)/2, chúng ta có thể
bảo rằng nó khoảng chừng N2/2.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 51


Phân tích một giải thuật lặp
 Ví dụ 1: Cho một giải thuật tìm phần tử lớn nhất
trong một mảng 1 chiều.
procedure MAX(A, n, max)
/* Set max to the maximum of A(1:n) */
begin
integer i, n;
max := A[1];
for i:= 2 to n do
if A[i] > max then max := A[i]
end
 Nếu C(n) là độ phức tạp tính toán của giải thuật
được tính theo thao tác so sánh (A[i]> max). Hãy xác
định C(n) trong trường hợp xấu nhất.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 52


Phân tích một giải thuật lặp
 Thao tác căn bản của thủ tục MAX là thao tác so
sánh.
 Tổng số thao tác so sánh của thủ tục MAX chính là
số lần thân vòng lặp được thực thi: (n-1).
 Vậy độ phức tạp tính toán của giải thuật là O(n).
 Đây là độ phức tạp của cả hai trường hợp trung
bình và xấu nhất.
 Ghi chú: Nếu thao tác căn bản là phát biểu gán
(max := A[i]) thì O(n) là độ phức tạp trong trường
hợp xấu nhất.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 53


Phân tích một giải thuật lặp
 Ví dụ 2: Giải thuật kiểm tra xem có phải mọi phần tử
trong mảng 1 chiều là khác biệt nhau.
function UniqueElements(A, n)
begin
for i:= 1 to n –1 do
for j:= i + 1 to n do
if A[i] = A[j] return false
return true
end
 Trong trường hợp xấu nhất, mảng không hề có hai
phần tử nào bằng nhau hoặc mảng có hai phần tử
cuối cùng bằng nhau. Lúc đó một sự so sánh diễn ra
mỗi khi thân vòng lặp trong được thực hiện.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 54


Phân tích một giải thuật lặp
i=1 j chạy từ 2 cho đến n tức n – 1 lần so sánh
i=2 j chạy từ 3 cho đến n tức n – 2 lần so sánh
.
.
i = n -2 j chạy từ n-1 cho đến n tức 2 lần so sánh
i = n -1 j chạy từ n cho đến n tức 1 lần so sánh
Tóm lại, tổng số lần so sánh là:
1 + 2 + 3 + … + (n-2) + (n-1) = n(n-1)/2
Vậy độ phức tạp tính toán của giải thuật trong trường hợp xấu
nhất là O(n2).

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 55


Phân tích một giải thuật lặp
 Ví dụ 3: (So trùng dòng ký tự - string matching) Tìm
tất cả những sự xuất hiện của một khuôn mẫu
(pattern) trong một văn bản (text).
 Văn bản là một mảng T[1..n] gồm n ký tự và kiểu
mẫu là một mảng P[1..m] gồm m ký tự.
 Kiểu mẫu P xuất hiện với độ dịch chuyển (shift) s
trong văn bản T (tức là, P xuất hiện bắt đầu từ vị trí
s+1 trong văn bản T) nếu 1 ≤ s ≤ n – m và
T[s+1..s+m] = P[1..m].

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 56


Phân tích một giải thuật lặp
 Một giải thuật đơn giản nhất để tìm tất cả những sự
xuất hiện của P trong T sẽ dùng một vòng lặp mà
kiểm tra điều kiện P[1..m] = T[s+1..s+m] với mỗi trị
trong n – m + 1 trị có thể có của s.
procedure NATIVE-STRING-MATCHING(T,P);
begin
n: = |T|; m: = |P|;
for s:= 0 to n – m do
if P[1..m] = T[s+1,..,s+m] then
print “Pattern occurs with shift” s;
end

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 57


Phân tích một giải thuật lặp
procedure NATIVE-STRING-MATCHING(T,P);
begin
n: = |T|; m: = |P|;
for s:= 0 to n – m do
begin
exit:= false; k:=1;
while k ≤ m and not exit do
if P[k] ≠ T[s+k] then exit := true
else k:= k+1;
if not exit then
print “Pattern occurs with shift” s;
end
end

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 58


Phân tích một giải thuật lặp
 Giải thuật NAIVE STRING MATCHER có hai vòng
lặp lồng nhau:
- Vòng lặp ngoài lặp n – m + 1 lần.
- Vòng lặp trong lặp tối đa m lần.
 Do đó, độ phức tạp của giải thuật trong trường
hợp xấu nhất là: O((n – m + 1)m).

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 59


Phân tích độ phức tạp trung bình
 Để tính độ phức tạp trung bình của một giải thuật
A, ta phải làm một số bước:
- Quyết định một không gian lấy mẫu (sampling space) để diễn
tả những dữ liệu đầu vào (kích thước n) có thể có. Giả sử
không gian lấy mẫu là S = { I1, I2,…, Ik}
- Ta phải định nghĩa một phân bố xác xuất p trên S mà biểu
diễn mức độ chắc chắn mà dữ liệu đầu vào đó có thể xảy ra.
- Ta phải tính tổng số tác vụ căn bản được giải thuật A thực
hiện để xử lý một trường hợp mẫu. Ta dùng v(Ik) ký hiệu tổng
số tác vụ được thực hiện bởi A khi dữ liệu đầu vào thuộc
trường hợp Ik.
- Ta tính trị trung bình của số tác vụ căn bản bằng cách tính kỳ
vọng sau:
Cavg(n) = v(I1).p(I1) + v(I2).p(I2) + …+v(Ik).p(Ik).

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 60


Ví dụ: Tìm kiếm tuần tự
 Giả sử X có xuất hiện trong mảng và giả định rằng
xác xuất để nó xuất hiện tại một vị trí bất kỳ trong
mảng là đều nhau và xác xuất để mỗi trường hợp
xảy ra là p = 1/n.
- Số lần so sánh để tìm thấy X nếu nó xuất hiện tại vị trí 1 là 1
- Số lần so sánh để tìm thấy X nếu nó xuất hiện tại vị trí 2 là 2
- …
- Số lần so sánh để tìm thấy X nếu nó xuất hiện tại vị trí n là n
 Tổng số tác vụ so sánh trung bình là:
C(n) = 1.(1/n) + 2.(1/n) + …+ N.(1/n)
= (1 + 2 + …+ n).(1/n)
= (1+2+…+n)/n = n(n+1)/2.(1/n) = (n+1)/2.

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 61


Hàm số sử dụng tính toán
 Tổng chuỗi số điều hoà (Harmonic sum)
 Hn = 1 + 1/2 + 1/3 + 1/4 +…+1/n
 Hn = loge n + γ
 γ ≈ 0.577215665 được gọi là hằng số Euler.
 Một chuỗi số khác cũng rất thông dụng khi phân tích
các thao tác làm việc trên cây nhị phân:
 1 + 2 + 4 +…+ 2m-1 = 2m -1

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 62


Bài tập
 Phân tích độ phức tạp giải thuật của một vài chuỗi số thông
dụng sau:
 Chuỗi số cộng
S1 = 1 + 2 + 3 + … + n
S1 = n(n+1)/2 ≈ n2/2
S2 = 1 + 22 + 32 + …+ n2
S2 = n(n+1)(2n+1)/6 ≈ n3/3
 Chuỗi số nhân
S = 1 + a + a2 + a3 + … + an
S = (an+1 -1)/(a-1)
If 0< a < 1, then
S ≤ 1/(1-a)
Và khi n → ∞, S tiến về 1/(1-a).

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 63


Bài tập
 1. Tinh chỉnh lại đoạn chương trình sau:

for (int i=0; i < n; i++)
{
if ( flag)
b[i] = 0;
a[i] = a[i] + b[i];
c[i] = a[i] + 2*b[i];
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 64


Bài tập
 2. Tinh chỉnh lại đoạn chương trình sau:
...
while ( sqrt( i*i) < sqrt (a*a) )
{
// đoạn chương trình
….
i++;
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 65


Bài tập
 3. Tinh chỉnh lại đoạn chương trình sau:
...
flag = FALSE;
k =0;
while ( k < n)
{
if (a[i] == x)
flag = TRUE;
k++;
}
if (flag)
printf("Tim thay phan tu!");

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 66


Bài tập
 4. Tinh chỉnh lại đoạn chương trình sau:
...
while ( i < n)
{
d = sqrt (a+b)*i;
printf("gia tri %.2f", d);
i++;
}
...

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 67


Bài tập
 5. Tinh chỉnh lại đoạn chương trình sau:
...
for(int i=0; i < strlen(strBuff); i++)
{
….
}

Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 68


Cấu trúc dữ liệu 2008 - Văn Thiên Hoàng - Khoa CNTT 69

You might also like