1
Cấutrúcdữ liệu
và giảithuật
Ngườithựchiện: GVC. TS. Nguyễn Trung Hòa
Email:
Điệnthoại: 0904 162168
Tài liệuthamkhảo
1. Cấutrúcdữ liệuvàgiảithuật
Đỗ Xuân Lôi, NXB ĐHQGHN,2004
2. Cẩm nang thuật toán
R. Sedgewick, NXB Khoa họcvàKỹ
thuật,1994
Đề cương chương trình
2
Chương 1. Giảithuật
1.1. Khái niệmgiảithuật
1.2. Thiếtkế giảithuật
1.3. Phân tích và đánh giá giảithuật
1.1. Khái niệmgiảithuật
1.1.1. Giảithuậtlàgì?
1.1.2. Cấutrúcdữ liệu
1.1.3. Diễn đạtgiảithuật
3
1.1.1. Giảithuậtlàgì?
1.1.1. Giảithuậtlàgì?
Ví dụ mởđầu
Cho một dãy các số thựca
1
,a
2
,…,a
n
. Tìm giá trị
lớnnhấtm củacácsốđã cho và chỉ số lớnnhấti
trong các sốđạtgiátrị m.
Vì phảitìmsố lớnnhấtvớichỉ số lớnnhất, ta sẽ
xuất phát từ số cuốicùngcủadãylàa
n
và sẽ so
sánh với các số trước đó, khi tìm thấymộtgiátrị
lớnhơnthìtaghi lại (đánh dấu) và lạitiếptụcso
sánh số này với các số trước đó, công việcsẽ
đượcthựchiệnchođếnkhiđãso vớisốđầutiên.
4
1.1.1. Giảithuậtlàgì?
Giảithuậtlà:
Cách làm để giải quyết bài toán
Một dãy có trình tự các thao tác trên mộtsốđối
tượng nào đósaochosau mộtsố hữuhạnbước
thựchiện ta đạt đượckếtquả mong muốn.
Mộtgiảithuậtcó
Đầu vào (Input): tậpcácđốitượng (dữ liệu)
Đầu ra(Output): mộttập các giá trị (thông tin)
Các bướcthựchiện
Vào Ra
1.1.1. Giảithuậtlàgì?
Các đặctrưng củagiảithuật
Tính có đạilượng vào/ra
Tính xác định
Tính hữuhạn(tínhdừng)
Tính tổng quát
Tính hiệuquả
Mộtvàiđặc điểmcầnlưuý
Không cầnbiếtgiátrị cụ thể củakếtquả sau mỗibước, chỉ
cầnbiết cách chuyểntừ bướctrướctớibước sau;
Kếtquả cụ thể củagiảithuậtcóthể không phảilàkếtquả
đúng (chính xác) mặcdầuphương pháp là đúng.
5
1.1.2. Cấutrúcdữ liệu
Dữ liệucócấutrúc:
Tậphợpdữ liệu
Có mốiquanhệ với nhau trong bài toán xác định
Lựachọncấutrúcdữ liệuvàgiảithuậtthíchhợp: rất
quan trọng
Vídụ: viếtchương trình tìm kiếmsốđiệnthoại theo tên đơn
vị
Giảithuật+ Dữliệu= Chương trình
Biểudiễncấutrúcdữ liệu trong bộ nhớ:
Lưutrữ trong
Thông qua các biến
Lưutrữ ngoài
Tệp(định kiểuvàkhôngđịnh kiểu)
1.1.3. Diễn đạtgiảithuật
Ngôn ngữ tự nhiên
Ngôn ngữ liệtkêcácbước
6
1.1.3. Diễn đạtgiảithuật
Giả ngôn ngữ (máy tính)
Chú thích: /*…*/ hoặc//…
Các đoạncủathuật toán có thểđược đánh số thứ tự.
Ký tự và biểuthức
26 chữ cái Latin + 10 chữ số
Phép toán số học: +, -, *, /, ^(lũythừa), %
Phép toán quan hệ: <, >, ==, <=, >=, !=
Phép toán logic: &&, ||, !
Giá trị logic: true, false
Biến đượcchỉ số hóa: a
i
, a
ij
Thứ tựưutiêncủa các phép toán:
như trong ngôn ngữ C và các ngôn ngữ chuẩnkhác
Lệnh gán: a = b;
Khốilệnh: { S1; S2; S3; }
1.1.3. Diễn đạtgiảithuật
Lệnh điềukiện:
if (B) S;
if (B) {s1;s2;s3;}
if (B) S1; else S2;
Lệnh lặp
for (i = 0 ; i<n; i++)
S;
for ( i = n; i>= 0; i )
S;
do S while (B);
while (B) S;
7
1.1.3. Diễn đạtgiảithuật
Lệnh vào/ra:
read (<danh sách biến>)
write (<danh sách biếnhoặcdòngkýtự>)
Chương trình con:
function <tên hàm> (<danh sách tham số>)
{
S1; S2; …Sn;
return; // nếuchương trình con trả lạimộtgiátrị
}
Gọichương trình con:
<tên hàm> (<danh sách tham số thựcsự>)
1.1.3. Diễn đạtgiảithuật
lưu đồ
Mộtsố ký hiệuquyước
Lệnh điềukhiểncóthể là:
Khốilệnh
Lệnh điềukiện
Lệnh lặp
Bắt đầu/ kết thúc
Điềukiện
Lệnh vào, lệnh ra
Lệnh gán
Nốitiếp đoạnlệnh
Luồng thựchiện
8
1.1.3. Diễn đạtgiảithuật
Khốilệnh
Cú pháp:
{
S1;
S2;
S3;
}
S1
S2
S3
1.1.3. Diễn đạtgiảithuật
Lệnh điềukiện
Cúpháp
If (điều_kiện)
hành_động
if (B)
S1
Else
S2;
S2 S1
B
9
1.1.3. Diễn đạtgiảithuật
Lệnh lặp
Cúpháp:
while (B)
S;
for (khởi_tạo;
điều_kiện; cập_nhật)
hành_động
1.1.3. Diễn đạtgiảithuật
Do hành_động
While (điều_kiện)
10
1.1.3. Diễn đạtgiảithuật
Ngôn ngữ lậptrình
Cài đặtgiảithuật: ngôn ngữ C/C++
1.2. Thiếtkế giảithuật
1.2.1. Mô đun hóa và việcgiải quyết bài toán
1.2.2. Phương pháp tinh chỉnh từng bước
(Stepwise Refinement)
1.2.3. Ví dụ
11
1.2.1. Mô đun hóa và việcgiảiquyết
bài toán
Module hóa bài toán
Chia bài toán lớn (module chính) thành các bài toán (module)
nhỏ hơn
Mỗi module thựchiện công việccụ thể nào đó
Lặp đilặplạichođến khi các module là cô đọng, đơnthể và biết
cách giảiquyết.
=> chiếnthuật“Chiađể trị”
1.2.1. Mô đun hóa và việcgiảiquyết
bài toán
ThiếtkếTopdown – từđỉnh xuống, hay từ khái
quát đếnchi tiết.
Bước1: Xác định dữ kiện đầuvào, yêucầu đặtra
Bước2: Xác định các công việcchủ yếu(mỗi công việc
tương đương với 1 module)
Bước3: Giải quyếttừng công việcmột cách chi tiết
bằng cách lặp đilặplạibước 1 + 2
Ví dụ: Bài toán “Quảnlývàbảotrìcáchồ sơ về
họcbổng củasinhviên, thường kỳ lập báo cáo
tổng kết”.
12
1.2.1. Mô đun hóa và việcgiảiquyết
bài toán
ThiếtkếTopdown – Bước1
Bước1: Xácđịnh dữ kiện đầu vào và các yêu cầu
đặtra
Đầu vào: Tập các file bao gồm các thông tin vềhọcbổng
củasinhviên: MãSV, ĐiểmTB, MứcHB
Yêu cầu:
Tìm kiếmvàhiểnthị thông tin củabấtkỳ sinh viên nào
Cậpnhật thông tin củamột sinh viên cho trước
In bảntổng kết
1.2.1. Mô đun hóa và việcgiảiquyết
bài toán
ThiếtkếTopdown – Bước2
Bước2: Xácđịnh các công việcchủ yếu
Đọc các thông tin của sinh viên từ file vào bộ nhớ trong
(Đọc file)
Xử lý các thông tin (Xử lý thông tin)
Lưu thông tin đãcậpnhật vào file (Ghi file)
13
1.2.1. Mô đun hóa và việcgiảiquyết
bài toán
Thiếtkế Topdown – Bước3
Bước3: Lặplạibước1 + 2
Đọc file:
Đầu vào: File thông tin trên đĩa
Yêu cầu: Đọc file và lưuvàomảng: mỗiphầntử mảng lưu
thông tin củamột sinh viên
Đãcôđọng
Ghi file:
Đầuvào: Mảng lưuthôngtin của các sinh viên
Yêu cầu: Lưutrở lại file
Đãcôđọng
1.2.1. Mô đun hóa và việcgiảiquyết
bài toán
Xửlý TT
Đầu vào: Mảng lưu thông tin của các sinh viên
Yêu cầu:
Tìm một sinh viên cho trước
Hiểnthị thông tin củasinhviên
Cậpnhật thông tin của sinh viên
In bảntổng kết
14
1.2.2 Phương pháp tinh chỉnh từng bước
Ban đầugiảithuật đượctrìnhbàyở dạng ngôn ngữ
tự nhiên
Chi tiết hóa dần–tinhchỉnh hướng về phía ngôn
ngữ lậptrình
Giai đoạntrunggian–giả ngôn ngữ
1.2.3. Ví dụ
Bài toán: “Sắpxếpmột dãy n số nguyên theo thứ tự tăng dần”
Ngôn ngữ tự nhiên củagiảithuật:
Từ dãy số nguyên chưa đượcsắpxếpchọnrasố nhỏ nhấtvà
đặtvàođầudãyđã đượcsắpxếp
Loạisố nguyên đórakhỏi dãy chưa đượcsắpxếp
Lặplạichođếnkhidãychưa đượcsắpxếplàrỗng
15
1.2.3. Ví dụ
Cấutrúcdữ liệu:
Dãy số ban đầu đượclưutrữ trong mộtmảng mộtchiều
Dãy đãsắpxếpsẽđượclưu trùng với dãy chưasắpxếp
=> Giảithuật: Đặtsố nhỏ nhấtcủalượtthứ i vào dãy đãsắp
xếpbằng cách đổichỗ vớisố thứ i trong dãy
Giả ngôn ngữ
Tinh chỉnh lần1
For (i=0; i<n; i++)
{
1. Xét từ a
i
đếna
n-1
để tìm số nhỏ nhấta
j
2. Đổichỗ a
i
và a
j
}
1.2.3. Ví dụ
Tinh chỉnh lần2
Giảithuậtbước1: Xéttừ a
i
đếna
n-1
để tìm số nhỏ nhấta
j
Coi a
i
là “số nhỏ nhất” ( j = i)
So sánh “số nhỏ nhất” và a
i+1
, số nào nhỏ hơnthìcoilà“số
nhỏ nhất” (nếua
i+1
< a
j
thì j = i+1)
Tiếptục so sánh “số nhỏ nhất” vớia
i+2
, a
i+3
, …a
n-1
, a
n
Xác định “số nhỏ nhất” bằng cách nắm đượcchỉ số củanó
Tinh chỉnh bước1
j = i;
for (k = i+1; k<n; k++)
If (a
k
< a
j
) j = k;
16
1.2.3. Ví dụ
Giảithuậtbước2: Đổichỗ a
i
và a
j
, sử dụng mộtbiến
trung chuyển
Tinh chỉnh bước2
tmp = a
i
;
a
i
= a
j
;
a
j
= tmp;
Tinh chỉnh lần3
function SapXep(a, n)
/* a là mảng các số nguyên, n là số phầntử mảng */
{
For (i = 0; i<n; i++)
{
1.2.3. Ví dụ
/* 1. Tìm số nhỏ nhất*/
j = i;
for (k = i+1; k<n; k++)
If (a
k
< a
j
) j = k+1;
/* 2. Đổichỗ*/
tmp = a
i
;
a
i
= a
j
;
a
j
= tmp;
}
}
Bài tập: Trình bày ngôn ngữ tự nhiên, các bước tính chỉnh và
giảithuật để giải bài toán: “Cho một dãy các số nguyên
a
1
,a
2
,…,a
n
. Tìm giá trị lớnnhấtm củacácsốđã cho và chỉ số
lớnnhất i trong các sốđạtgiátrị m.
17
Giảibàitập
Ngôn ngữ tự nhiên
Vì phảitìmsố lớnnhấtvớichỉ số lớnnhất, ta sẽ xuất phát từ số cuối
cùng của dãy là a
n
và sẽ
so sánh với các số trước đó, khi tìm thấymộtgiátrị lớnhơnthìtaghi lại
(đánh dấu) và lạitiếptục so sánh số này với các số trước đó,
công việcsẽđượcthựchiệnchođếnkhiđãso vớisốđầutiên.
Tinh chỉnh lần đầu.
0) xuất phát từ số cuốicùngcủa dãy là a
n
(i=n) và tạmthời coi giá trị lớn
nhấtm làa
n
, tất nhiên lúc này k=n;
1) Xét i=i-1;
2) Nếu i=0, thì viếtrak, m (việc tìm là xong - thuật toán kếtthúc).
3) Nếungượclại thì (so sánh a
i
vớim)
Nếua
i
> m thì coi m là a
i
, k=i
Quay lại 1) (Chuyển qua xét số trướcsố thứ i).
Giảibàitập
Tinh chỉnh lần1:
i=n; m=a
i
i=i-1;
While (i != 0) do
{
(1). Nếum<a
i
thì ghi lạim=a
i
và i
(2). Giảmi
}
Tinh chỉnh lần2:
Tinh chỉnh bước(1).
If (m<a
i
)
{
m=a
i
;
k=i
}
Tinh chỉnh bước(2).
i=i-1
Tinh chỉnh lần3:
function timmax(a,n,m,k);
/* a là mảng các số nguyên, n
là kích thước dãy, m là giá
trị lớnnhất, k là vị trí cực
đại*/
{
i=n; m=a
i
i=i-1;
While (i > 0)
{
If (m<a
i
)
{
m=a
i
;
k=i;
}
i=i-1;
}
}
18
1.3. Phân tích giảithuật
1.3.1. Tạisaocần phân tích giảithuật?
1.3.2. Phân tích thuậttoán
1.3.3. Độ phứctạpgiảithuật
1.3.1.Tại sao cần phân tích giảithuật?
Viếtmộtchương trình chạythônglàchưa đủ
Chương trình có thể thựchiệnchưahiệuquả!
Nếuchương trình chạytrênmộttậpdữ liệulớn, thì
thờigianchạysẽ là mộtvấn đề cầnlưuý
Vídụ: Bài toán lựachọn
Cho một dãy gồmN số, hãy tìm phầntử lớnthứ k,
vớik ≤N.
Thuật toán1:
(1) ĐọcN số vào mộtmảng
(2) Sắpxếpmảng theo thứ tự giảmdần
(3) Trả lạiphầntửởvị trí thứ k
19
1.3.1.Tại sao cần phân tích giảithuật?
Thuật toán2:
(1) Đọck phầntửđầutiênvàomảng và sắpxếp chúng
theo thứ tự giảmdần
(2) Mỗiphầntử còn lạichỉđọcmộtlần
Nếuphầntửđólànhỏ hơnphầntử thứ k, bỏ qua
Ngượclại, đặtnóvàovị trí phù hợpcủamảng, đẩyphần
tử hiệntạirakhỏimảng.
(3) Phầntử tạivị trí thứ k là phầntử cầntìm.
1.3.1.Tại sao cần phân tích giảithuật?
Thuật toán nào là tốthơnkhi
N =100 và k = 100?
N =100 và k = 1?
Điềugìsẽ xảy ra khi N = 1,000,000 và k =
500,000?
Còn có những thuậttoántốthơn?
20
1.3.2. Phân tích thuậttoán
Đốitượng phân tích
Chúng ta chỉ phân tích những thuậttoánđúng
Mộtthuật toán là đúng?
Nếu,vớimộtdữ liệu đầu vào, thuậttoándừng và đưarakếtquả
đúng
Thuật toán không đúng
Có thể không dừng vớimộtsố dữ liệu đầuvào
Dừng nhưng đưarakếtquả sai
Dựđoán lượng tài nguyên mà thuậttoányêucầu
Tài nguyên gồm
Bộ nhớ
Băng thông giao tiếp
Thời gian tính –ThờigianthựchiệnGT(thường là quan trọng nhất)
1.3.2. Phân tích thuật toán
Thờigianthựchiệngiảithuật
Các nhân tốảnh hưởng đếnthời gian tính
Máy tính
Chương trình dịch
Thuậttoánđượcsử dụng
Dữ liệu đầuvàocủathuậttoán
Giá trịcủadữ liệu ảnh hưởng đếnthờigiantính
Thông thường, kích thướccủadữ liệu đầuvàolà nhân tố
chính quyết định thờigiantính
Với bài toán sắpxếp: số phầntử cầnsắpxếp
Với bài toán nhân ma trận: kích thước(số phầntử) của
2 ma trận
21
1.3.2. Phân tích thuậttoán
Độ phứctạpvề thờigian
ThuậttoánA mất 2 phút để chạyvớidữ liệu đầuvàoX.
ThuậttoánB mất 1 phút 45 giây để chạyvới cùng dữ liệuX.
Liệu B có phảilàthuậttoán“tốthơn” A?
Không hẳnlànhư vậy!
Chỉ kiểmtravớimộtbộ dữ liệu X. Có thể vớidữ liệuX nàyB chạy nhanh
hơn A, nhưng vớiphầnlớncácdữ liệu khác B chạychậmhơn A.
Thuật toán A bị ngắtbởicáctiến trình khác.
Thuật toán B đượcchạy trên máy tính cócấuhìnhcaohơn.
…
Phép đocầnphải không phụ thuộcvàomáy.
Đobằng cách đếm số các phép tính cơ sở (phép gán, phép so
sánh, các phép tính số học, v.v.).
Ta thường ký hiệu số lượng các phép tính, các thao tác cơ bản (gán,
so sánh) củamộtthuậttoánlà f(n).
1.3.2. Phân tích thuậttoán
Vídụ
Bài toán Tính tổng các số nguyên từ 1 đếnn.
Thuậttoán1
intsum = 0;
for (int i = 1; i <= n; i++)
sum = sum+ i;
Thuậttoán2
intsum = ((n+1)*n) / 2;
22
1.3.2. Phân tích thuậttoán
Trường hợptồinhất / trung bình / tốtnhất
Thờigiantínhtốtnhất: Thờigiantốithiểu cầnthiết để thựchiện
thuậttoánvớimọibộ dữ liệu đầuvàokíchthước n.
Thời gian tính tồinhất: Thời gian nhiềunhấtcầnthiết để thực
hiệnthuật toán vớimọibộ dữ liệu đầu vào kích thướcn.
Thời gian trung bình: cầnthiết để thựchiệnthuậttoántrêntập
hữuhạncácđầuvàokíchthước n.
Việcxácđịnh độ phứctạp tính toán nhiềukhicònphụ thuộcvào
tình trạng củadữ liệu. Do đótaphảixéttớif(n) trongtrường hợp
thuậnlợinhất, f(n) trong trường hợpxấunhất và f(n) trong
trường hợp trung bình. Tuy nhiên việcxácđịnh f(n) trong trường
hợp trung bình thường khó khăn. Vì vậy, trong các trường hợp
f(n) xác định khó khăntalấy f(n) trong trường hợpxấunhất để
đánh giá độ phứctạp tính toán củagi
ảithuật.
1.3.2. Phân tích thuậttoán
Điều quan trọng đốivớigiảithuậtlà
Mất bao nhiêu giây để chạyvớidữ liệu đầu vào có kích
thước n?
Thờigiantínhphụ thuộc vào kích thướcdữ liệu đầuvào
Mộtsố tốc độ thay đổicủathời gian tính khi n tăng.
Thuật toán có thờigianhằng số: nếuthờigianchạycủanó
là không đổi khi kích thướcdữ liệu thay đổi.
Thuật toán có thờigiantuyến tính: nếuthờigianchạycủa
nó tỷ lệ thuậnvới n.
Thuậttoáncóthờigiantínhlàhàmsố mũ nếuthờigian
chạytăng theo mộthàmsố mũ của n.
23
1.3.3. Độ phứctạpgiảithuật
Định nghĩabậcO-lớn
Giả sử f(n) và g(n) là hai hàm xác định trên mộttậphợpcácsố
nguyên dương. Ta nói rằng f(n) có bậcO-lớncủag(n), và viết
f(n)=O(g(n)) hoặcf=O(g) nếutồntạihằng số C>0 sao cho vớin
đủ lớn, các hàm f(n) và g(n) đềudương, đồng thời f(n)<Cg(n).
O(g) đặctrưng cho độ tăng của hàm.
Ví dụ. Nếu f(n) là đathứca
d
n
d
+a
d-1
n
d-1
+…+a
1
n+a
0
trong đóa
d
>0
thì f(n)=O(n
d
)
Mộtvàitínhchất
Nếuf
1
(n)=Og(n), f
2
(n)=Og(n) thì f
1
+f
2
=O(g)
Nếuf
1
=O(g
1
), f
2
=O(g
2
) thì f
1
f
2
=O(g
1
g
2
)
Nếutồntạigiớihạn thì f=O(g)
Vớimọisố ε>0 thì log(n)=O(n
ε
)
)(
)(
lim
ng
nf
n ∞→
1.3.3. Độ phứctạpgiảithuật
Định nghĩa
Mộtthuật toán đượcgọilàcóđộ phứctạp đathức (hoặc
gọilàcóthờigianđathức) nếusố phép tính cầnthiết để
thựchiệnthuật toán không vượt quá O(log
d
(n)), trong đón
là độ lớncủadữ liệu đầu vào và d là số nguyên dương nào
đó.
Để ướclượng độ phứctạpcủagiảithuậtngườita
thường so sánh khốilượng tính toán f(n) củamột
giảithuậtvớimột hàm g(n) nào đó thông qua bậcO-
lớncủa g(n), mà thông thường g(n) là các hàm sau
đây (vớithứ tự có độ tăng lớndần):
24
1.3.3. Độ phứctạpgiảithuật
g(n)=1; thờigianhằng số
g(n)=logn; thời gian logarit
g(n)=n; thờigiantuyến tính
g(n)=nlogn;
g(n)=n
2
; bình phương
g(n)=n
2
logn;
g(n)=n
3
; mũ 3
g(n)=2
n
; hàm số mũ n
g(n)=n!giaithừa
1.3.3. Độ phứctạpgiảithuật
Bảng minh họa độ phứctạpcủagiảithuật
Độ phứctạp
f(n)
25
1.3.3. Độ phứctạpgiảithuật
Định nghĩa
Giả sử f(n) và g(n) là hai hàm xác định trên một
tậphợpcácsố nguyên dương. Ta nói rằng f(n) có
bậc Omega-lớncủag(n), và viếtf(n)=Ω(g(n)) hoặc
f= Ω(g) nếutồntạihằng số C>0 sao cho vớin đủ
lớn, các hàm f(n) và g(n) đềudương, đồng thời
f(n)>Cg(n).
Điều đó có nghĩalàf(n) tăng không chậmhơn
g(n) vớin đủ lớn
Tốc độ tăng của f(n) lớnhơnhoặcbằng tốc độ
tăng của g(n).
1.3.3. Độ phứctạpgiảithuật
Định nghĩa
Giả sử f(n) và g(n) là hai hàm xác định trên mộttậphợp
các số nguyên dương. Ta nói rằng f(n) có bậc Theta-lớn
củag(n), và viết f(n)=Θ(g(n)) hoặc f= Θ(g) nếuthỏamãn
đồng thời f(n)= O(g(n)) và f(n)= Ω(g(n)).
Điều đócónghĩalàf(n) giaođộng chung quanh g(n) vớin
đủ lớn
Tốc độ tăng củaf(n)bằng tốc độ tăng của g(n).
Mộtsốquy tắc
Nếu f(n) làmột đathứcbậc k, thì f(n) = Θ(n
k
).
Với các hàm logarit log
m
n= Θ(log n).