Ạ Ọ Ạ Ọ
ƯỜ ƯỜ
NG Đ I H C AN GIANG NG Đ I H C AN GIANG Ậ Ậ
Ệ Ệ
TR TR Ỹ Ỹ
ƯỜ ƯỜ
KHOA K THU T CÔNG NGH MÔI TR KHOA K THU T CÔNG NGH MÔI TR
NG NG
Ữ Ệ Ữ Ệ
Ấ Ấ
C U TRÚC D LI U 1 C U TRÚC D LI U 1
Giảng viên phụ trách:
HUỲNH CAO THẾ CƯỜNG
Bộ môn Tin học
email: hctcuong@agu.edu.vn
11
Chương 1. TỔNG QUAN CẤU TRÚC DỮ LIỆU Chương 1. TỔNG QUAN CẤU TRÚC DỮ LIỆU
Cấu trúc dữ liệu (Data Structures) Kiểu dữ liệu trừu tượng (Abstract Data Type - ADT) Giải thuật (Algorithms) Tính toán độ phức tạp của giải thuật (Computational
complexity of algrorithms)
Phân tích giải thuật (Algorithm Analysis)
2
Cấu trúc dữ liệu (Data Structures) Cấu trúc dữ liệu (Data Structures)
là một tập hợp.
Cấu trúc dữ liệu dùng để tổ chức dữ liệu Thường có nhiều hơn một thành phần Có các thao tác hợp lý trên dữ liệu Dữ liệu có thể được kết nối với nhau (ví dụ: array) như
3
Kiểu dữ liệu trừu tượng (ADT) Kiểu dữ liệu trừu tượng (ADT)
Một kiểu dữ liệu trừu tượng (Abstract Data Type - ADT) là tập hợp các đối tượng và được xác định hoàn toàn bởi các phép toán có thể biểu diễn trên các đối tượng đó.
ADT là một mô hình toán của cấu trúc dữ liệu xác định kiểu dữ liệu được lưu trữ, các thao tác được hỗ trợ trên dữ liệu đó và kiểu của các tham số trong từng thao tác.
4
Kiểu dữ liệu trừu tượng (ADT) Kiểu dữ liệu trừu tượng (ADT)
Đơn/nguyên tử: int, char, … Có cấu trúc: array, struct,…
Có hai loại ADT
Ngoài những ADT do ngôn ngữ lập trình cung cấp, người lập trình có tạo ra các ADT của riêng mình
Trong C, các ADT do người dùng định nghĩa sẽ thông qua kiểu cấu trúc (struct), các thao tác được xây dựng bằng các hàm (functions)
5
Kiểu dữ liệu trừu tượng (ADT) Kiểu dữ liệu trừu tượng (ADT)
Tạo lập đối tượng mới Biến đổi các đối tượng của ADT
– Mang lại những thay đổi cần thiết cho đối tượng
Quan sát
– Cho biết trạng thái của đối tượng
Chuyển đổi kiểu
– Chuyển kiểu từ kiểu này sang kiểu khác
Vào ra dữ liệu
– Nhập/xuất giá trị cho đối tượng
Các lớp thao tác của một ADT
6
Kiểu dữ liệu trừu tượng (ADT) Kiểu dữ liệu trừu tượng (ADT)
Cấu thành bởi: – Họ tên – Ngày sinh – Nơi sinh – Phái Phép toán:
– Tạo mới một person (với thông tin đầy đủ) – Hiển thị thông tin về một person – ….
Person
7
Tại sao cần phải học Cấu trúc dữ liệu và Giải Tại sao cần phải học Cấu trúc dữ liệu và Giải thuật? thuật?
Tại sao lại cần phải học giải thuật? Vai trò của giải
thuật? Những vấn đề nào sẽ cần giải quyết bằng giải thuật? Giải thuật:
Là một khái niệm quan trọng nhất trong tin học. Thuật ngữ này xuất phát từ nhà tóa học Ảrập Abu Ja’far Mohammed ibn Musa al Khowarizmi (khoảng năm 825)
Thuật toán nổi tiếng nhất, có từ thời kỳ cổ Hy Lạp là
thuật toán Euclid.
Giải thuật?
Là một phương pháp giải quyết vấn đề thích hợp để 8
cài đặt như một chương trình máy tính.
Tại sao cần phải học Cấu trúc dữ liệu và Giải Tại sao cần phải học Cấu trúc dữ liệu và Giải thuật? thuật?
A finite sequence of steps for solving a logical or mathematical problem or performing a task. (The Microsoft Computer Dictionary, Fifth Edition )
A computable set of steps to achieve a desired result. Informally, an algorithm is any well-defined
computational procedure that takes some value, or set of values, as input and produces some value, or set of values, as output. An algorithm is thus a sequence of computational steps that transform the input into the output (Introduction to Algorithms, 2nd, Thomas H. Cormen, 2001)
Algorithm:
9
Tại sao cần phải học Cấu trúc dữ liệu và Giải Tại sao cần phải học Cấu trúc dữ liệu và Giải thuật? thuật?
Được tạo ra để phục vụ cho các giải thuật Phải hiểu cấu trúc dữ liệu để hiểu giải thuật (cid:0)
để giải
quyết vấn đề
Các giải thuật đơn giản có thể cần đến cấu trúc dữ liệu
phức tạp
Các giải thuật phức tạp có thể chỉ dùng các cấu trúc
dữ liệu đơn giản
Cấu trúc dữ liệu?
ữ ệ ấ ả ươ C u trúc d li u + Gi ậ i thu t = Ch ng trình
10
Kiểu dữ liệu Kiểu dữ liệu
Tên kiểu dữ liệu Miền giá trị Kích thước lưu trữ Tập các toán tử, phép toán tác động trên kiểu dữ liệu
ĐN kiểu dữ liệu Các thuộc tính của 1 kiểu dữ liệu
Kiểu chuỗi ký tự (string), Kiểu mảng (array) Kiểu mẩu tin (struct) Kiểu tập hợp (union)
Một số kiểu dữ liệu có cấu trúc cơ bản
11
Tại sao cần phải học Cấu trúc dữ liệu và Giải Tại sao cần phải học Cấu trúc dữ liệu và Giải thuật? thuật?
Giải quyết các vấn đề về tính toán? Việc giải quyết vấn đề nhanh hơn? Khả năng truy xuất nhiều dữ liệu hơn?
Dùng máy tính để:
Kỹ thuật có thể tăng khả năng giải quyết vấn đề
bằng nhân tố hằng.
Thiết kế giải thuật tốt có thể giúp giải quyết vấn đề
tốt hơn nhiều và có thể rẻ hơn.
Một siêu máy tính không thể giúp một giải thuật tồi
làm việc tốt hơn
Kỹ thuật vs. Thực thi/Giá
12
Một số tính chất chung Một số tính chất c
của các thuật toán hung của các thuật toán
Đầu vào (input): có các giá trị đầu vào xác định. Đầu ra (ouput): từ tập các giá trị đầu vào, thuât toán sẽ tạo các
giá trị đầu ra, xem là nghiệm của bài toán.
Tính xác định (definiteness): các bước của thuật toán phải được
xác định một cách chính xác.
Tính hữu hạn (finiteness): một thuật toán chứa một số hữu hạn
các bước (có thể rất lớn) với mọi tập đầu vào.
Tính hiệu quả(effectiveness): mỗi bước phải thực hiện chính xác,
trong khoảng thời gian hữu hạn.
Tính tổng quát(general): thuật toán phải áp dụng được cho một
họ các vấn đề.
13
Ví dụVí dụ
Ví dụ: Mô tả thuật toán tìm phần tử lớn nhất trong một
đầu tiên.
Bước 2: Nếu số nguyên kế tiếp lớn hơn giá trị cực đại
tạm thời thì gán giá trị cực đại tạm thời bằng số nguyên đó.
Bước 3: Lặp lại bước 2 nếu còn số nguyên trong dãy. Bước 4: Dừng khi không còn số nguyên trên dãy. Số nguyên lớn nhất trong dãy là giá trị cực đại tạm thời.
dãy hữu hạn các số nguyên Bước 1: Đặt giá trị cực đại tạm thời bằng số nguyên
14
Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân
// Tìm tuyến tính
linearSearch(int a[], int x, int n)
int {
i = 0;
int while (i < n) && (a[i] != x)
i++;
return (i == n);
}
15
Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân
// Tìm nhị phân
int binarySearch(int a[], int x, int n)
{
left = 0, right = N - 1, middle;
int do {
middle = (left + right) / 2; if (a[middle] == x)
return TRUE; else if (x < a[middle])
right = middle – 1;
else left = middle + 1;
} while (left <= right); return FALSE;
}
16
Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân
Với tìm kiếm tuần tự, giả sử x không có trong mảng a,
giải thuật phải xử lý đầy đủ n lần.
Với tìm kiếm nhị phân, dù x có hay không có trong a thì
số lần tìm kiếm tối đa chỉ là log2n = 5.
Để so sánh hai giải thuật, sử dụng n = 32
17
Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân Ví dụ so sánh - Tìm tuyến tính và tìm nhị phân
Tuần tự
Nhị phân
n
256
256
8
1024
1024
10
1048576
1048576
20
4.294.967.296 4.294.967.296
32
18
Ví dụ so sánh - Fibonacci Ví dụ so sánh - Fibonacci
// Tính Fibonacci(n) int fib1(int n) if (n <= 1) {
return n;
else
return fib1(n - 1) + fib1(n - 2);
}
i (cid:0) n) được tính trong
Gọi T(n) là số lượng các Fi (0 (cid:0) giải thuật đệ qui: T(n) > 2n/2
19
Ví dụ so sánh - Fibonacci Ví dụ so sánh - Fibonacci
// Tính Fibonacci(n) int fib2(int n) {
f[0] = 0; f[1] = 1; for (i = 2; i <= n; i++)
f[i] = f[i - 1] + f[i - 2];
return f[n];
}
20
Ví dụ so sánh - Fibonacci Ví dụ so sánh - Fibonacci
n
n + 1
2n/2
fib2()
fib1()
40
41
1,048,576
41 ns
1048 μs
60
61
1.1 × 109
61 ns
1 s
80
81
1.1 × 1012
81 ns
18 min
100
101
1.1 × 1015
101 ns
13 days
120
121
1.2 × 1018
121 ns
36 years
160
161
1.2 × 1024
161 ns
3.8 × 107 years
200
201
1.3 × 1030
201 ns
4 × 1013 years
21
Phân tích thuật toán Phân tích thuật toán
Độ phức tạp về không gian (space complexity) Độ phức tạp về thời gian (time complexity) Độ phức tạp về giải thuật (complexity of algorithm)
22
space complexity) Độ phức tạp về không gian ((space complexity) Độ phức tạp về không gian
Bộ nhớ Sử dụng CPU Băng thông …
Chiếm tài nguyên của máy:
23
time complexity) Độ phức tạp về thời gian ((time complexity) Độ phức tạp về thời gian
Tính hiệu quả của giải thuật được kiểm tra bằng
phương pháp thực nghiệm, thông qua các bộ dữ liệu thử: Phụ thuộc vào ngôn ngữ lập trình. Trình độ, kỹ năng có được của người viết. Phần cứng (máy tính) dùng để thử nghiệm. Sự phức tạp của việc xây dựng một bộ dữ liệu thử.
24
Tiêu chuẩn đánh giá một giải thuật là tốt Tiêu chuẩn đánh giá một giải thuật là tốt
Một giải thuật được xem là tốt nếu nó đạt các tiêu
chuẩn sau: Thực hiện đúng. Tốn ít bộ nhớ. Thực hiện nhanh.
Trong khuôn khổ môn học này, chúng ta chỉ quan tâm
đến tiêu chuẩn thực hiện nhanh.
25
complexity of Độ phức tạp về giải thuật ((complexity of Độ phức tạp về giải thuật algorithm) algorithm)
Mang tính hình thức. Phép đo độc lập với máy tính, ngôn ngữ máy tính,
người lập trình, … hay những “tiểu tiết”: tăng/giảm chỉ số vòng lặp, sự khởi tạo, gán, …
Thời gian thực thi của một giải thuật sẽ tăng theo kích thước dữ liệu và thời gian này tỉ lệ với số lượng các thao tác cơ sở.
Độ phức tạp của giải thuật là một hàm số trên kích
thước dữ liệu.
26
complexity of Độ phức tạp về giải thuật ((complexity of Độ phức tạp về giải thuật algorithm) algorithm)
Những thao tác cơ sở có thể là:
- Phép so sánh - Phép chuyển dời - Phép toán số học, …
Thao tác cơ sở là thao tác mang lại hiệu quả cao nhất.
Trong các giải thuật sắp xếp, hai thao tác cơ bản là: so
sánh và chuyển dời.
27
Độ phức tạp giải thuật (Algorithm Complexity) Độ phức tạp giải thuật (Algorithm Complexity)
Đơn vị đo thời gian thực hiện:
– T(n) trong đó n là kích thước (độ lớn) của dữ liệu
vào. T(n) ≥ 0 với mọi n ≥ 0.
Thông thường người ta tính thời gian thực hiện xấu
nhất (the worst case):
– T(n) là thời gian lớn nhất để thực hiện chương trình
đối với mọi dữ liệu vào có cùng kích thước n.
Thời gian thực hiện chương trình (Running Time).
28
Tỷ suất tăng (growth rate) Tỷ suất tăng (growth rate)
T(n) có tỷ suất tăng f(n) nếu tồn tại các hằng số C và
N0 sao cho T(n) ≤ Cf(n) với mọi n ≥ N0.
Giả sử T(0) = 1, T(1) = 4, tổng quát T(n) = (n+1)2 Ðặt N0 = 1 và C = 4 thì n ≥1, ∀ Ta có T(n) = (n+1)2 ≤ 4n2 với mọi n ≥ 1, tức là tỷ suất
tăng của T(n) là n2.
Ví dụ:
T(n) = 3n3 + 2n2 là n3. Cho N0 = 0 và C = 5 ta có với
mọi n ≥ 0 thì 3n3 + 2n2 ≤ 5n3
Ví dụ:
29
Khái niệm độ phức tạp của giải thuật
P1: T1(n) = 100n2 (tỷ suất tăng là n2) P2 : T2(n) = 5n3 (tỷ suất tăng n3). Giải thuật nào sẽ thực hiện nhanh hơn?
Với n < 20 thì P2 sẽ nhanh hơn P1 (T2 Giả sử ta có hai giải thuật P1 và P2 Cho một hàm T(n), T(n) gọi là có độ phức tạp f(n) nếu
tồn tại các hằng C, N0 sao cho T(n) ≤ Cf(n) với mọi n ≥
N0 (tức là T(n) có tỷ suất tăng là f(n)) và kí hiệu T(n) là
O(f(n)) (đọc là “ô của f(n)”) Khái niệm: Ví dụ: T(n)= (n+1)2 có tỷ suất tăng là n2 nên T(n)= (n+1)2 là O(n2) Chú ý: O(C.f(n))=O(f(n)) với C là hằng số. Ðặc biệt O(C)=O(1) hàm thể hiện độ phức tạp có các dạng thường gặp sau: log2n, n, nlog2n, n2, n3, 2n, n!, nn. Nếu T1(n) và T2(n) là thời gian thực hiện của hai đoạn chương trình P1 và P2; và T1(n)=O(f(n)),
T2(n)=O(g(n)) thì thời gian thực hiện của đoạn hai
chương trình đó nối tiếp nhau là
T(n)=O(max(f(n),g(n))) Ví dụ: Lệnh gán x:=15 tốn một hằng thời gian hay O(1), và lệnh đọc dữ liệu scanf(“%d”,&x) tốn một hằng
thời gian hay O(1).Vậy thời gian thực hiện cả hai lệnh
trên nối tiếp nhau là O(max(1,1))=O(1) Qui tắc cộng Nếu T1(n) và T2(n) là thời gian thực hiện của hai đoạn chương trình P1và P2 và T1(n) = O(f(n)), T2(n) =
O(g(n)) thì thời gian thực hiện của đoạn hai đoạn
chương trình đó lồng nhau là T(n) = O(f(n).g(n)) Qui tắc nhân: Qui tắc tổng quát để phân tích một chương trình: lệnh gán, scanf, printf là O(1)
chuỗi tuần tự các lệnh được xác định bằng qui tắc cộng
=> Như vậy thời gian này = thời gian thi hành một lệnh
nào đó lâu nhất. Thời gian thực hiện cấu trúc IF là thời gian lớn nhất thực
hiện lệnh sau THEN hoặc sau ELSE và thời gian kiểm tra
điều kiện. Thường thời gian kiểm tra điều kiện là O(1).
Thời gian thực hiện vòng lặp là tổng (trên tất cả các lần lặp) thời gian thực hiện thân vòng lặp. Nếu thời gian thực
hiện thân vòng lặp không đổi thì thời gian thực hiện vòng
lặp là tích của số lần lặp với thời gian thực hiện thân
vòng lặp. void BubbleSort(int list[], int n)
{ int i,j,temp; for(i=0;i<(n-1);i++)
for(j=0;j<(n-(i+1));j++) (1)
(2)
(3)
(4)
(5)
(6) O((n-i).1) = O(n-i)
O(1)
O(1)
O(1)
O(1) if(list[j] > list[j+1])
{ temp = list[j];
list[j]= list[j+1];
list[j+1]= temp;
} } Giả sử ta có hai giải thuật P1 và P2 với thời gian thực
hiện tương ứng là T1(n) = 100n2 (với tỷ suất tăng là n2)
và T2(n) = 5n3 (với tỷ suất tăng là n3). Khi n>20 thì T1 < T2. Sở dĩ như vậy là do tỷ suất tăng của T1 nhỏ hơn tỷ suất tăng của T2. Như vậy một cách hợp lý là ta xét tỷ suất tăng của hàm
thời gian thực hiện chương trình thay vì xét chính bản
thân thời gian thực hiện. Cho một hàm T(n), T(n) gọi là có độ phức tạp f(n) nếu
tồn tại các hằng C, N0 sao cho T(n) ≤ Cf(n) với mọi n
≥ N0 (tức là T(n) có tỷ suất tăng là f(n)) và kí hiệu T(n)
là O(f(n)) (đọc là “ô của f(n)”). Chú ý: O(C.f(n))=O(f(n)) với C là hằng số. Ðặc biệt O(C)=O(1) Các hàm thể hiện độ phức tạp có các dạng thường gặp sau: log2n, n, nlog2n, n2, n3, 2n, n!, nn. Ba hàm cuối cùng ta gọi là dạng hàm mũ, các hàm khác gọi là hàm đa thức. Một giải thuật mà thời gian thực hiện có độ phức tạp là
một hàm đa thức thì chấp nhận được, còn các giải
thuật có độ phức tạp hàm mũ thì phải tìm cách cải tiến
giải thuật. Trong cách viết, ta thường dùng logn thay thế cho log2n cho gọn. Thủ tục sắp xếp “nổi bọt”
Ví dụ 1: Thủ tục sắp xếp “nổi bọt”
Ví dụ 1: for(i= 0; i<=n-2; i++)
for(j=n-1; j>=i+1;j--)
if (a[j].key < a[j-1].key) {
temp = a[j-1]; a[j] = temp; void BubbleSort(int a[n])
{ int i,j,temp;
/*1*/
/*2*/
/*3*/
/*4*/
/*5*/ a[j-1] = a[j];
/*6*/
}
} Tính thời gian thực hiện của thủ tục sắp xếp “nổi bọt”
Tính thời gian thực hiện của thủ tục sắp xếp “nổi bọt” Đây là 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}. Trước hết, cả ba 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) lần, mỗi lần O(1) do đó vòng lặp {2} tốn O((n-i).1) = O(n-i). Vòng lặp {1} có i chạy từ 1 đến n-1 nên thời gian thực hiện
của vòng lặp {1} và cũng là độ phức tạp của giải thuật là 1n 1) (cid:0) (cid:0) T(n) (n i) 2
)O(n (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) n(n
2 1i (cid:0) linearSearch(int a[], int x, int n) return 1; int
{
/* 1*/ int index = 0;
/* 2*/ while (index < n) {
/* 3*/
/* 4*/ if (a[index] = = x)
index ++; } return 0; /* 5*/
} Ta thấy các lệnh {1}, {2}, và {5} nối tiếp nhau, do đó độ phức
tạp của hàm linearSearch chính là độ phức tạp lớn nhất
trong 3 lệnh này. Dễ dàng thấy rằng ba lệnh {1}, {5} đều có
độ phức tạp O(1) do đó độ phức tạp của hàm linearSearch
chính là độ phức tạp của lệnh {2}. Lồng trong lệnh {2} là
lệnh {3} và {4}. Lệnh {3}, {4} có độ phức tạp O(1). Lệnh {2} là một vòng lặp không xác định, nên ta không biết
nó sẽ lặp bao nhiêu lần, nhưng trong trường hợp xấu nhất
(tất cả các phần tử của mảng a đều khác x, ta phải xét hết
tất cả các a[i], i có các giá trị từ 0 đến n-1) thì vòng lặp {2}
thực hiện n lần, do đó lệnh {2} tốn O(n). Vậy ta có T(n) =
O(n). void ExchangeSort(int n, int a[]) { for (i = 0; i < n - 1; i++) for (j = i + 1; j< n; j++) if (a[j] < a[i])
swap(a[i], S[j]); } )1 (cid:0) n n nT
)( ( )1 ( )2 1 nn
(
2 (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) void MatrixMult(int n, A[][], B[][], C[][])
{ for (i = 0; i < n; i++) for (j = 0; j < n; j++)
{ C[i][j] = 0;
for (k = 0; k < n; k++)
C[i][j] = C[i][j] + A[i][k] * B[k][j]; } 3 } (cid:0) (cid:0) (cid:0) (cid:0) Giả sử ta có một hệ thống các chương trình gọi nhau theo sơ đồ sau Có thể thấy hình ảnh chương trình đệ quy A như sau: Để phân tích các các chương trình đệ quy ta cần: Thành lập phương trình đệ quy.
Giải phương trình đệ quy, nghiệm của phương trình đệ
quy sẽ là thời gian thực hiện của chương trình đệ quy. 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 Ví dụ : Chương trình đệ quy tính n! int Giai_thua(int n) {
if (n==0) return 1;
else return (n* Giai_thua(n-1)); }; Trong ví dụ trên, n=0 là trường hợp dừng và k=n-1. Thành lập phương trình đệ quy
Thành lập phương trình đệ quy Phương trình đệ quy là một 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, ta phải căn cứ vào chương trình đệ quy. Ứng với trường hợp đệ quy dừng, ta phải xem xét khi đó
chương trình làm gì và tốn hết bao nhiêu thời gian, chẳng
hạn thời gian này là c(n). Khi đệ quy chưa dừng thì phải xét xem có bao nhiêu lời gọi đệ quy với kích thước k ta sẽ có bấy nhiêu T(k). Ngoài ra ta còn phải xem xét đến 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 thời gian này là
d(n). Thành lập phương trình đệ quy
Thành lập phương trình đệ quy Dạng tổng quát của một phương trình đệ quy sẽ là: (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) C(n) là thời gian thực hiện chương trình ứng với trường hợp đệ quy dừng. F(T(k)) là một đa thức của các T(k).
d(n) là thời gian để phân chia bài toán và tổng hợp các kết quả. Ví dụ về phương trình đệ quy của chương trình đệ quy tính
Ví dụ về phương trình đệ quy của chương trình đệ quy tính
n!n! Gọi T(n) là thời gian tính n!.
Thì T(n-1) là thời gian tính (n-1)!.
Trong trường hợp n = 0 thì chương trình chỉ thực hiện một lệnh return 1, nên tốn O(1), do đó ta có T(0) = C1.
Trong trường hợp n>0 chương trình phải gọi đệ quy Giai_thua(n-1), việc gọi đệ quy này 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à return tích số. Thời gian để thực hiện phép nhân và return là một hằng C2. Vậy ta có phương trình: 0=n C
1 (cid:0) T(n) n C1)T(n 0 2 (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) Giải thuật MergeSort
Giải thuật MergeSort List MergeSort (List L; int n){
List L1,L2
if (n==1) RETURN(L);
else { Chia đôi L thành L1 và L2, với độ dài n/2;
RETURN(Merge(MergeSort(L1,n/2),MergeSort(L2,n/2))); };
};
Hàm MergeSort nhận một danh sách có độ dài n và trả về một danh sách đã được sắp xếp. Thủ tục Merge nhận hai danh sách đã được sắp 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ự. Mô hình minh hoạ Mergesort
Mô hình minh hoạ Mergesort Sắp xếp danh sách L gồm 8 phần tử 7, 4, 8, 9, 3, 1, 6, 2 7 4 8 9 3 1 6 2 8 9 6 2 7 4 3 1 7 4 8 9 3 1 6 2 8 9 1 3 4 7 2 6 4 7 8 9 1 2 3 6 1 2 3 4 6 7 8 9 Phương trình đệ quy của giải thuật MergeSort
Phương trình đệ quy của giải thuật MergeSort Gọi T(n) là thời gian thực hiện MergeSort một danh sách n phần tử Thì T(n/2) là thời gian thực hiện MergeSort một danh sách n/2 phần tử. Khi L có độ dài 1 (n = 1) thì chương trình chỉ làm một
việc duy nhất là return(L), việc này tốn O(1) = C1 thời
gian. Trong trường hợp n > 1, chương trình phải thực hiện
gọi đệ quy MergeSort hai lần cho L1 và L2 với độ dài
n/2 do đó thời gian để gọi hai lần đệ quy này là 2T(n/2). Phương trình đệ quy của giải thuật MergeSort
Phương trình đệ quy của giải thuật MergeSort Ngoài ra còn phải tốn thời gian cho việc chia danh
sách L thành hai nửa bằng nhau và trộn hai danh
sách kết quả (Merge). Người ta xác định được thời gian để chia danh sách và Merge là O(n) = C2n . Vậy ta có phương trình đệ quy như sau: 1n C
1 (cid:0) (cid:0) (cid:0) nT 2T n 1 n C
2 n
2 (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) (cid:0) Giải phương trình đệ quy
Giải phương trình đệ quy Phương pháp truy hồi.
Phương pháp đoán nghiệm.
Lời giải tổng quát của một lớp các phương trình Có ba phương pháp giải phương trình đệ quy: Trường hợp tốt nhất (best case complexity) Trường hợp trung bình (average case complexity) Trường hợp xấu nhất (worst case complexity) Tên gọi thông thường (name) Ký hiệu ô lớn (Big-O Notation)
- Function Hằng (constant) Logarit (logarithmic) Log-squared Tuyến tính (Linear) n logarit Bình phương (Quadratic) Lập phương (Cubic) Mũ (exponential) Là thời gian lâu nhất của các lệnh trong vòng lặp Luật 1: Cho các vòng lặp Phân tích từ trong ra ngòai. Thời gian thực hiện bằng tích thời gian các vòng lặp.
Luật 3: Cho các lệnh liên tiếp nhau
Theo phương pháp cộng (max) Luật 2: Cho các vòng lặp lồng nhau Thời gian : O(n2)
for( i=0; i for( j=0; j Thời gian O(n2) – phương pháp phép cộng (max) for( i=0; i a[i] += a[j] + i + j;30
Khái niệm độ phức tạp của giải thuật
31
Tính toán độ phức tạp (Computational Complexity)
32
Tính toán độ phức tạp (Computational Complexity)
33
Tính toán độ phức tạp (Computational Complexity)
34
Tính toán độ phức tạp (Computational Complexity)
35
Khái niệm độ phức tạp của giải thuật
Khái niệm độ phức tạp của giải thuật
36
Khái niệm độ phức tạp của giải thuật
Khái niệm độ phức tạp của giải thuật
37
38
39
Tính độ phức tạp của hàm tìm kiếm tuần tự
Tính độ phức tạp của hàm tìm kiếm tuần tự
40
Tính độ phức tạp của hàm tìm kiếm tuần tự
Tính độ phức tạp của hàm tìm kiếm tuần tự
41
complexity of
Độ phức tạp về giải thuật ((complexity of
Độ phức tạp về giải thuật
algorithm)
algorithm)
42
complexity of
Độ phức tạp về giải thuật ((complexity of
Độ phức tạp về giải thuật
algorithm)
algorithm)
nnn
n
nT
)(
43
Ðộ phức tạp của chương trình
Ðộ phức tạp của chương trình
có gọi chương trình con không đệ qui
có gọi chương trình con không đệ qui
B
B1
B11
A
C
B2
B12
44
Phân tích các chương trình đệ qui
Phân tích các chương trình đệ qui
A
45
46
47
T(n)
C(n)
F(T(k))
d(n)
48
49
50
7 4 8 9 3 1 6 2
51
52
53
đệ quy.
54
Các mức đánh giá
Các mức đánh giá
55
Các cấp thời gian thực hiện thuật toán
Các cấp thời gian thực hiện thuật toán
(Typical growh rates)
(Typical growh rates)
O(1) hay C
O(logn)
O(log2n)
O(n)
O(nlogn)
O(n2)
O(n3)
O(2n)
56
Qui tắc tính thời gian
Qui tắc tính thời gian
57
Qui tắc tính thời gian
Qui tắc tính thời gian
58