Tải bản đầy đủ (.doc) (14 trang)

Phân tích và đánh giá thuật toán bài toán tìm kiếm

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (113.58 KB, 14 trang )

MỤC LỤC
NỘI DUNG.........................................................................................................................................................1
PHẦN I: MỘT SỐ THUẬT TOÁN CƠ BẢN.......................................................................................................1
1. Thuật toán.............................................................................................................................................3
2. Biễu diễn thuật toán.............................................................................................................................5
Phần II: BÀI TOÁN TÌM KIẾM........................................................................................................................8
3. Đánh giá hiệu quả của thuật toán........................................................................................................8
4. Giải thuật tìm kiếm...............................................................................................................................8
PHẦN III: BÀI TOÁN ÁP DỤNG....................................................................................................................11
1.Phát biểu bài toán...............................................................................................................................11
TÀI LIỆU THAM KHẢO......................................................................................................................................14

NỘI DUNG
PHẦN I: MỘT SỐ THUẬT TOÁN CƠ BẢN

1


Việc sử dụng máy tính điện tử để giải quyết một bài toán nào đó thường được hiểu
một cách không đầy đủ. Nhiều người cho rằng đó chỉ là việc lập trình thuần túy. Thực ra,
giải một bài toán trên máy tính điện tử là một quá trình phức tạp, bao gồm nhiều giai
đoạn phát triển, mà lập trình chỉ là một trong các giai đoạn đó.
Ta hãy xét bài toán giải hệ phương trình đại số tuyến tính trên máy tính. Đây là
một bài tập khá quen thuộc đối với sinh viên các chuyên ngành kỹ thuật. Với một đầu vào
như vậy, không ít sinh viên cho rằng chỉ còn một việc duy nhất, đó là viết chương trình.
Về mặt lý thuyết, toán học đã giải quyết khá đầy đủ: từ phát biểu bài toán, thuật toán và
xây dựng các phân tích về nghiệm của hệ phương trình trong các trường hợp khác nhau.
Nhưng khi viết chương trình trên máy tính để giải bài toán trên sẽ có một số vấn đề phải
làm rõ. Thậm chí có những vấn đề gặp phải ngay từ khi viết những dòng đầu tiên trong
chương trình như kích thước của hệ phương trình chẳng hạn. Số ẩn và số phương trình tối
đa là bao nhiêu? Nếu để ý tiếp ta sẽ thấy ngay một số thông tin mà người lập trình phải


biết như: Số ẩn và số phương trình có bằng nhau hay không? Trong trường hợp hệ có
nhiều nghiệm thì phải viết ra bao nhiêu nghiệm và những nghiệm nào? Dữ liệu về các hệ
số của phương trình được nhập từ tệp hay từ bàn phím? Giá trị các hệ số đó có quá lớn,
quá nhỏ không?
Như vậy, rõ ràng là với một bài toán, người lập trình cần có đầy đủ những thông
tin về những yêu cầu chi tiết của đầu bài liên quan đến giới hạn của bộ nhớ, giới hạn của
màn hình, giới hạn về thời gian và giới hạn về sai số. Trong một số trường hợp những
thông tin này được xác định ngay trong đầu bài nhưng trong nhiều trường hợp phải qua
một quá trình phân tích mới làm rõ được các thông tin này.
Người lập trình phải giải quyết một vấn đề, một bài toán trên máy tính cần phải
thực hiện một bước rất quan trọng, đó là phân tích bài toán. Việc phân tích đầu bài nhằm
làm rõ một số thông tin:
a) Yêu cầu của bài toán: Bài toán đòi hỏi giải quyết cái gì trên máy tính. Nếu
giải quyết vấn đề này trên máy tính thì có gặp khó khăn gì về bộ nhớ, về thời gian tín, về
cách giải quyết?
b) Dữ liệu đầu vào và dữ liệu đầu ra của bài toán là gì và như thế nào?
2


c) Với cách giải quyết đã được lựa chọn có sẵn thuật toán hỗ trợ hay không?
Trả lời được một số câu hỏi trên người lập trình mới có thể viết được chương
trình đáp ứng yêu cầu đề ra trong bài toán.
1. Thuật toán
Thuật toán là một bản liệt kê các chỉ dẫn, các quy tắc cần thực hiện theo từng bước
xác định nhằm giải quyết một bài toán đã cho trong một khoảng thời gian hữu hạn.
Ví dụ 1: Tìm số lớn nhất trong một dãy hữu hạn các số nguyên.
Thuật toán:
1) Đặt giá trị cực đại tạm thời bằng số nguyên đầu tiên trong dãy.
2) So sánh số nguyên tiếp theo với giá trị cực đại tạm thời, nếu lớn hơn giá trị
cực đại tạm thời thì đặt giá trị cực đại tạm thời bằng số nguyên đó.

3) Lặp lại bước 2) nếu còn các số nguyên trong dãy.
4) Giá trị cực đại tạm thời ở thời điểm này chính là số nguyên lớn nhất trong
dãy.
Trên đây là những chỉ dẫn cụ thể từng bước được thể hiện bằng ngôn ngữ thông
thường. Chúng ta sẽ tìm cách thể hiện lại thuật toán giải bài toán trên theo cách thức
khác:
-

Dữ liệu vào (input): A là mảng chứa n số nguyên.
Dữ liệu ra (output): max, số lớn nhất trong mảng A.
Procedure Tim_max (A: mảng có n số nguyên);
a) Đặt max:= A (1);
b) Xét từ i = 2 đến n
Nếu max < A (i) thì đặt max:=A(i);

Bảng mô tả thuật toán có các yếu tố:
a) Tính xác định: Các bước của thuật toán phải được xác định một cách chính xác,
các chỉ dẫn phải rõ ràng, có thể thực hiện được.
b) Tính hữu hạn: Thuật toán phải kết thúc sau một số hữu hạn bước.
c) Tính đúng đắn: Thuật toán phải cho kết quả đúng theo yêu cầu của bài toán đặt
ra.
d) Tính tổng quát: Thuật toán phải áp dụng được cho mọi bài toán cùng loại, với
mọi dữ liệu đầu vào như đã được mô tả.
Khi mô tả một thuật toán cần đảm bảo các yếu tố sau đây:

3


- Dữ liệu đầu vào: Một thuật toán phải mô tả rõ các giá trị đầu vào từ một tập hợp
các dữ liệu xác định. Ví dụ, dãy số nguyên a(1), a(2),…,a(n), với n<∞; hai số nguyên

dương a và b.
- Dữ liệu đầu ra: Từ một tập các giá trị đầu vào, thuật toán sẽ tạo ra các giá trị
đầu ra. Các giá trị đầu ra chính là nghiệm của bài toán. Ví dụ, số max là phần tử lớn nhát
trong a(1), a(2),…,a(n); số d là ước chung lớn nhất của a và b.
Ta xét thuật toán tìm số lớn nhất trong một dãy số nguyên nêu ở ví dụ trên:
- Tính xác định: Mỗi bước của thuật toán chỉ gồm các phép gán, mệnh đề kéo theo.
- Tính hữu hạn: Thuật toán dừng sau khi tất cả các thành phần của mảng đã được
kiểm tra.
- Tính đúng đắn: Sau mỗi bước kiểm tra và so sánh ta sẽ tìm được số lớn nhất
trong các số đã được kiểm tra. Rõ ràng, sau lần kiểm tra cuối cùng thì xác định được số
lớn nhất trong toàn bộ các số đã được kiểm tra, có nghĩa là toàn bộ dãy.
- Tính tổng quát: Thuật toán cho phép tìm số lớn nhất của dãy số nguyên hữu hạn
n bất kỳ.
Dữ liệu đầu vào đầu ra được mô tả rõ ràng:
+ Dữ liệu đầu vào: Mảng chứa n số nguyên.
+ Dữ liệu đầu ra: Số nguyên lớn nhất của mảng đầu vào.
Ví dụ 2: Cho dãy số nguyên A và số nguyên x. Hãy xác định xem số nguyên x có trong
mảng A hay không. Nếu có, hãy chỉ ra vị trí của x trong mảng A.
Thuật toán:
-

Input: Mảng A gồm n các số nguyên và số nguyên x.
Output: Chỉ số Index của x nếu thấy hoặc -1 nếu không tìm được x.

Procedure Timkiem_TT (A: Mảng số nguyên; x: số nguyên):
+ Index:=1;
+ While (Index <=n) and (x# A (Index)) Do Index:=Index + 1;
+ If Index > n Then Index:=-1;
Thuật toán tìm kiếm nêu trên được gọi là thuật toán tìm kiếm tuần tự hay còn gọi
là tìm kiếm tuyến tính.


4


Ví dụ 3: Cho mảng số nguyên A đã được sắp xếp không gian và số nguyên x. Hãy xác
định xem số nguyên x có trong mảng A hay không. Nếu có, hãy chỉ ra vị trí của x trong
mảng A.
Dữ liệu đầu vào của bài toán này khác với bài toán trước ở chỗ mảng A được sắp
xếp không giảm. Nhờ thế mà chúng ta có thể lựa chọn thuật toán tìm kiến nhị phân để
giải bài toán này.
Thuật toán:
- Input: Mảng A gồm n các số nguyên đã được sắp xếp tăng dần và số nguyên x
cần tìm trong danh sách.
- Output: Chỉ số Index, chỉ số Index bằng chỉ số phần tử bằng x, hoặc bằng 0 nếu
không tìm dược x.
Prucedure Timkiem_NP(A: mảng số nguyên; x: số nguyên)
+ CS trái :=1; CS phải :=n;
+ Chưa tìm thấy :=True;
+ While (còn khoảng tìm) and (chưa tìm thấy) Do
• Index:= Chỉ số ở giữa CS trái và CS phải;
• If x =A(i) Then đặt chưa tìm thấy = false
Else khoảng tìm sẽ bị co hẹp;
If x< A(Index) Then CS phải = Index -1
Else CS trái = Index + 1;
+ If chưa tìm thấy Then đặt Index :=0;
Trước khi giải một bài toán trên máy tính người lập trình phải phân tích bài toán,
hiểu rõ các yêu cầu và ràng buộc của nó sau đó mới xây dựng thuật giải. Thuật giải cũng
có thể được lựa chọn trong các thuật toán quen biết, cũng có thể do người lập trình xây
dựng thông qua hiểu biết và cảm nhận của mình.
2. Biễu diễn thuật toán

Để có thể thảo luận về thuật toán (hay thuật giải) hoặc chuyển thuật toán thành
chương trình trên máy tính, người ta phải tìm cách biểu diễn thuật toán. Trong các ví dụ
được nêu chúng ta đã biểu diễn chính bằng ngôn ngữ gần tự nhiên hoặc ngôn ngữ gần với

5


ngôn ngữ lập trình (tựa ngôn ngữ lập trình hay còn gọi là giả mã). Trong phần này chúng
ta xem xét kỹ hai ngôn ngữ thường được dùng là sơ đồ khối và giả mã.
2.1. Sơ đồ khối
Sơ đồ khối là một ngôn ngữ dùng để biểu diễn thuật toán. Sơ đồ khối là một công
cụ giúp cho người lập trình có được một cách xem xét sự làm việc của thuật toán khá chi
tiết và cu thể. Sơ đồ khối được quy ước bao gồm các nút là hình elip, chữ nhật hoặc hình
thoi được nối với nhau bởi các đường chỉ hướng chuyển động trong sơ đồ.
Băt đầu
Kết thúc
-

Hai loại nút giới hạn Bắt đầu và Kết thúc thường có hình dạng elip;
Nút chỉ các thao tác, công việc có dạng hình chữ nhật;

i=i+1
- Nút chỉ các điều kiệnBắt
cóđầu
dạng hình thoi: Trong các đường nối với nút điều kiện
này có hai đường đi ra ứng với hai trường hợp điều kiện đúng hoặc điều kiện sai:
- Các đường nối các nút với nhau.
Nhập n, A[1…n]

max:= A(1)

i:=2

True
ĐK

S
False
Ví dụ, sơ đồ khối sau đây
mô tả thuật toán tìm giá trị lớn nhất trong mảng số A có
i<=n
n phần tử.
Đ
S
Max < A(i)

max:= A(i)

i := i + 1

6

In giá trị max

Kết thúc


Đ

2.2. Giả mã
a) Cấu trúc tuần tự: Liệt kê các công việc, các thao tác theo thứ tự. Để hỗ trợ cho việc

theo dõi được thuận tiện cũng có thể thêm số thứ tự.
b) Cấu trúc rẽ nhánh:
 If (điều kiện) Then (công việc);
 If (điều kiện) Then (công việc 1) Else (Công việc 2);
c) Cấu trúc lặp:





For (biến):= (giá trị đầu) to (giá trị cuối) do (công việc);
For (biến):= (giá trị đầu) downto (giá trị cuối) do (công việc);
While (điều kiện) do (công việc);
Repeat
- (công việc 1);
- (công việc 2);
- .....
- (công việc k);
Until (điều kiện);

2.3. Một số thuật toán quy hoạch động
- Bài toán nhân ma trận.
7


- Tìm đường đi ngắn nhất.
- Dãy con dài nhất.

Phần II: BÀI TOÁN TÌM KIẾM
1. Định nghĩa Bài toán tìm kiếm

Bài toán tìm kiếm là: Tìm kiếm một phương án, đáp án theo yêu cầu đầu vào.
VD:

- Cho một danh sách xác định vị trí xuất hiện của một phần tử trong danh sách.
- Tìm kiếm giải pháp lựa chọn để đạt giá trị cực đại trong bài toán cái túi.

Bài toán xảy ra trong hai tình huống:
- Dữ liệu xuất hiện được coi là ngẫu nhiên.
- Dữ liệu thỏa mãn một số ràng buộc nhất định.
2. Phân loại
-Tìm kiếm tuần tự
- Tìm kiếm nhị phân
- Tìm kiếm dựa trên quy hoạch
.......
3. Đánh giá hiệu quả của thuật toán
Tính hiệu quả của thuật toán thông thường được đo bởi thời gian (thời gian được
sử dụng để tính bằng máy hoặc bằng phương pháp thủ công) – độ phức tạp thời gian, khi
các giá trị đầu vào có kích thước xác định. Tính hiệu quả của thuật toán cũng được xem
xét theo thước đo dung lượng bộ nhớ đã sử dụng để tính toán khi kích thước đầu vào đã
xác định – độ phức tạp không gian.
Độ phức tạp không gian gắn liền với việc xem xét các cấu trúc dữ liệu đặc biệt
được dùng để thể hiện thuật toán.
Độ phức tạp thời gian của một thuật toán thường được biểu diễn thông qua số
phép toán trong khi thực hiện thuật toán khi các giá trị dữ liệu đầu vào có kích thước xác
định.
4. Giải thuật tìm kiếm
Bài toán
8



Giả sử R là mảng gồm n bản ghi, bản ghi thứ k có một khóa X(k), với k=1,2...,n. Hãy
tìm bản ghi có khóa bằng (hoặc bé hơn, lớn hơn) giá trị b cho trước.
Giá trị b được gọi là khóa tìm kiếm hay đối trị tìm kiếm. Bài toán được gọi là giải
xong nếu như tìm được bản ghi thứ k nào đó mà X(k) = b hoặc khẳng định được rằng
không có bản ghi nào thỏa mãn điều kiện đặt ra, tức là X(k) b với mọi k=1,2,...,n.
4.1.Tìm kiếm tuần tự (Sequential Searching)
Ý tưởng
Bắt đầu từ bản ghi thứ nhất (k=1), lần lượt so sánh khóa tìm kiếm b với khóa tương
ứng của các bản ghi trong mảng, cho tới khi hoặc là tìm được bản ghi thỏa mãn điều kiện
hoặc là hết mảng mà không thấy.
Thuật toán
Input: Mảng X[1..n], giá trị b
Output: Chỉ số k [1..n] mà tại đó X(k)=b hoặc 0 nếu X(k) b với k [1..n]
Function TKTT (X: mảng; b: Khóa tìm kiếm): Chỉ số;
Begin
k:=1;
While (X(k) b & (k

n) do k:=k+1;

If k=n+1 then TKTT:=0 else TKTT:=k;
End;
Đánh giá thuật toán
Trong trường hợp xấu nhất ta cần 2n phép so sánh. Tuy nhiên nếu ta thực hiện một
cải tiến nhỏ như sau:
Input: Mảng X[1..n+1], giá trị b
Output: Chỉ số k [1..n] mà tại đó X(k)=b hoặc 0 nếu X(k) b với k [1..n]
Function TKTT (X: mảng; b: Khóa tìm kiếm): Chỉ số;
Begin
9



X(n+1)=b; k:=1;
While X(k) b do k:=k+1;
If k=n+1 then TKTT:=0 else TKTT:=k;
End;
Thì trong trường hợp xấu nhất ta cần n+1 phép so sánh. Trong cả hai trường hợp ta
có độ phức tạp của thuật toán là O(n).
4.2. Tìm kiếm nhị phân
Ý tưởng
Trên các bản ghi mà khóa đã được sắp xếp tăng dần so sánh khóa tìm kiếm b với
khóa của bản ghi ở giữa của đoạn mảng đang xét. Chẳng hạn mảng đang xét là X[l..r] thì
phần tử (bản ghi) ở giữa là X(k) với k=(l+r)/2; nếu X(k)=b thì việc tìm kiếm kết thúc, nếu
X(k)hợp X(k)>b thì việc tìm kiếm sẽ được thực hiện trên mảng con X[k+1,r]. Quá trình tìm
kiếm trên mảng con sẽ được tiếp tục với thủ tục nêu trên.
Thuật toán
Input: Mảng X[1..n], giá trị b
Output: Chỉ số k [1..n] mà tại đó X(k)=b hoặc nếu X(k) b với k [1..n]
Function TKNP (b: Khóa tìm kiếm): Chỉ số;
Begin
TKNP:=0;
can_trai:=1; can_phai:=n;
While can_trai

can_phai do

Begin
K:=(can_trai + can+phai)/2;
If X(k) = b then

TKNP:=k;
Exit_loop;
Else If b< X(k) then can_phai:= k-1
Else can_trai:= k+1;
End
End;
Đánh giá thuật toán

10


Ta sẽ đánh giá vòng lặp mà thuật toán phải thực hiện. Giả sử n=2 d. Trong trường
hợp xấu nhất thuật toán thực hiện tới d vòng lặp. Mỗi vòng lặp có thể có tới 3 phép so
sánh. Như vậy số tối đa phép so sánh mà thuật toán phải thực hiện là 3d hay 3[log 2n]+3
với n tùy ý. Vậy độ phức tạp của thuật toán là O(log2n).

4.3. Tìm kiếm dựa trên quy hoạch động
Bài toán Dãy con dài nhất
Bài toán:
Cho dãy có n số S={X(1), X(2,....,X(n)}. Hãy tìm dãy con đơn điệu tăng (không giảm)
S’={X(p1), X(p2), ..., X(pn)}, với p1< p2<....< pk, có nhiều phần tử nhất, có nghĩa là k lớn
nhất.
Thuật toán:
1. Procedure Gán nhãn
{Kí hiệu L(i) – nhãn của X(i)}
1) L(1):= 1;
2) For i:=2 to n do
If (tồn tại X(j) với jL(i):= max {L(j)+1:X(j)< X(i), j=1,2,..., i-1}
Else L(i):= 1;


PHẦN III: BÀI TOÁN ÁP DỤNG
1. Phát biểu bài toán
Cho dãy X gồm n số nguyên n ≤ 1000000. Hãy tìm dãy con đơn điệu gồm các
phần tử liên tiếp của X sao cho có nhiều phần tử nhất. Ví dụ, nếu X = { 12, 2, 3, 4, 6, 7, 1,
9, 10 } thì dãy con cần tìm là {2, 3, 4, 6, 7} có 5 phần tử.
2. Nhận định ban đầu
-

Số dãy con của x:

Chúng ta có thể xem mỗi dãy con x của X tương đương với một chuỗi nhị phân b,
độ dài n trong đó, bi = 0 nghĩa là ai không thuộc a và ngược lại bi = 1 nghĩa là ai thuộc a.
11


Ví dụ nếu X = [1, 3, 2, 3] thì dãy con tương ứng với chuỗi nhị phân b = 1010 là [1, 3].
Như vậy, số dãy con của X cũng chính là số chuỗi nhị phân có độ dài n chính là 2 n. Mặc
dù có thể với 2 chuỗi nhị phân khác nhau sẽ tương ứng với cùng một dãy con (với
mảng X = [1, 3, 2, 3], hai chuỗi 1100 và 1001 cùng tương ứng với dãy con [1, 3]), nhưng
nếu lập trình bình thường để duyệt tất cả các dãy con của X thì phải duyệt 2 n phần tử.
Với n = 100 thì có đến 2100≈ 1030 dãy con.
-

Phương án khả thi:

Phương án duyệt tất cả các dãy con để tìm kết quả tối ưu có độ phức tạp là O (2 n),
rõ ràng là không khả thi khi n lớn. Do đó chúng ta sẽ sử dụng thuật toán quy hoạch động
để giải bài toán.
3. Ý tưởng

- Đầu tiên xét for (int i=1; i- Kiểm tra nếu a[i - 1] < = a [i] thì dãy tăng, ta thực hiện
{
maxT=lt[i-1]+1;
}
lt[i] = maxT;
if(maxT > maxTang)
{
maxTang = maxT;
}
Nếu a[i ] < = a [i - 1] thì dãy giảm, ta thực hiện
{
maxG=lg[i-1]+1;
}
lg[i]=maxG;

12


if(maxG > maxGiam)
{
maxGiam = maxG;
}
}
- Ta thực hiện xét các trường hợp như vậy cho đến phần tử cuối cùng. Sau đó so
sánh độ dài của các dãy con mà ta đã tìm được ở trên. Dãy nào có độ dài lớn nhất và liên
tiếp thì ta chọn. Nếu 2 dãy có độ dài bằng nhau thì kết quả sẽ trả ra cả 2 dãy.
4. Ví dụ mô phỏng thuật toán
Cho dãy X = { 12, 2, 3, 4, 6, 7, 1, 9, 10 } có giá trị i tương ứng từ 1 đến 9
i = 1, ta đưa 12 vào dãy, dãy có 1 phần tử

i = 2, ta xét 12< 2, dãy giảm, đưa 2 vào ta được dãy {12,2}
i = 3, ta thấy 2<3, dãy tăng, đưa 2,3 vào dãy ta được dãy mới {2,3}
i = 4, ta thấy 3< 4, dãy tăng, đưa 4 vào ta được dãy {2,3,4}
i = 5, ta thấy 4<6, dãy tăng, đưa 6 vào ta được {2,3,4,6}
i = 6, ta thấy 6< 7, dãy tăng, đưa 7 vào ta được {2,3,4,6,7}
i = 7, ta thấy 7> 1, dãy giảm, đưa 7,1 vào dãy mới {7,1}
i = 8, ta thấy 1< 9, dãy tăng, đưa 1,9 vào dãy mới {1,9}
i = 9, ta thấy 9< 10, dãy tăng, đưa 10 vào dãy ta được {1,9,10}
 Ta thấy dãy đơn điệu gồm các phần tử liên tiếp tăng dài nhất có 5 phần tử là dãy
{2,3,4,6,7}

13


TÀI LIỆU THAM KHẢO
1. Bài giảng cấu trúc dữ liệu và giải thuật – TS Đào Thanh Tĩnh – Trường học viện
kỹ thuật quân sự.
2. />3. />4. />5. Giải thuật và lập trình – Lê Minh Hoàng – Đại học sư phạm Hà Nội, 1999 - 2002

14