a. Khái niệm về Cơ Sở Dữ Liệu
I.3.4. Các hệ thống thông minh
Bài giảng tin học đại cương
Bài tập về Tin học căn bản (2 tiết BT)
…
BUỔI 6.
PHẦN II. GIẢI QUYẾT BÀI TOÁN
(8 tiết Lý thuyết, 2 tiết Bài tập)
II.1. Thuật toán(4 tiết LT) II.1.1. Định nghĩa thuật toán
Thuật toán là một khái niệm cơ sở của Toán học và Tin học. Nói một cách nôm na, thuật toán là một tập các lệnh hay chỉ thị nhằm hướng dẫn việc thực hiện một công việc nào đó. Chính xác hơn, thuật toán bao gồm một dãy hữu hạn các chỉ thị rõ rang và có thể thi hành được để hướng dẫn thực hiện hành động nhằm đạt được mục tiêu đề ra. Việc học hay nghiên cứu thuật toán giữ vai trò rất quan trọng trong khoa học máy tính vì máy tính có khả năng thực hiện công việc theo một thuật toán chỉ đạo nó phải từng bước làm gì. Về mặt phương pháp, ta có thể xem thuật toán như là sự thể hiện của một phương pháp để giải quyết một vấn đề.
Trong khoa học máy tính, thuật toán được định nghĩa là một dãy gồm các bước không mập mờ và có thể thực thi được. Hơn nữa quá trình hành động theo thuật toán phải dừng và cho kết quả như mong muốn.
Cụm từ “không mập mờ” trong định nghĩa thuật toán ở trên có nghĩa là: tại mỗi bước, hành động kế tiếp phải được xác định một cách duy nhất theo chỉ thị hành động và theo dữ liệu thích hợp ở thời điểm đó. Điều này không có nghĩa là mỗi chỉ thị hành động trong thuật toán phải xác định được hành động trong mỗi bước khi xét riêng. Ví dụ như chỉ thị hành động theo kiểu” Nếu… thì…” không đủ thông tin để xác định hành động cần phải thực hiện.
Theo định nghĩa trên đây thì dãy các bước sau đây: 1. Tạo danh sách tất cả các số nguyên dương 2. Sắp xếp danh sách theo thứ tự giảm dần
3. Lấy ra số nguyên đầu tiên từ danh sách đã được sắp xếp 4. Dừng
không phải là một thuật toán vì các bước 1 và 2 không thể thực hiện được.
Bài giảng tin học đại cương
Ví dụ về thuật toán:
Thuật toán tìm phần tử lớn nhất trong một dãy hữu hạn các số nguyên.
Bài toán tìm phần tử lớn nhất trong một dãy hữu hạn tương đối tầm thường. Tuy nhiên đây là một trong các ví dụ khá tốt để minh họa cho khái niệm về thuật toán. Có nhiều vấn đề mà trong đó đòi hỏi phải tìm ra số nguyên lớn nhất trong một dãy số. Chẳng hạn như việc tìm ra một học sinh có điểm số cao nhất trong một kỳ thi, hay tìm một nhân viên có năng suất cao nhấ trong một xí nghiệp…
Chúng ta có nhiều cách để giải bài toán này. Một trong các phương pháp để tìm phần tử lớn nhất trong một dãy số nguyên là thực hiện một thủ tục theo các bước sau đây:
1. Trước hết đặt cho giá trị lớn nhất tạm thời bằng số nguyên đầu tiên (Giá trị lớn nhất tạm thời này chính là giá trị lớn nhất ở mỗi giai đoạn của thủ tục.)
2. So sánh số nguyên kế tiếp trong dãy với giá trị lớn nhất tạm thời, và nếu nó lớn hơn giá trị lớn nhất tạm thời thì đặt cho giá trị lớn nhất tạm thời bằng số nguyên này.
3. Lặp lại bước 2 nếu còn số nguyên trong dãy chưa được xét tới.
4. Dừng nếu không còn số nguyên nào trong dãy chưa được xét tới. Giá trị lớn nhất tạm thời lúc này chính là giá trị lớn nhất trong dãy số.
Các đặc trưng của thuật toán:
Theo định nghĩa của thuật toán ra có thể thấy rằng: khi mô tả một thuật toán chúng ta cần chú ý đến các tính chất đặc trưng sau đây của thuật toán:
• Nhập (input): các thuật toán thường có các giá trị nhập (input values) từ một tập hợp nhất định nào đó.
• Xuất (output): Từ mỗi tập hợp các giá trị được nhập một thuật toán thường tạo ra những giá trị xuất (output values) thuộc một tập hợp nhất định nào đó thể hiện lời giải cho bài toán (hay vấn đề)
• Tính xác định (definiteness): Các bước trong thuật toán phải chính xác rõ ràng.
• Tính hữu hạn (finiteness): thuật giải phải cho ra lời giải (hay kết quả) sau một số hữu hạn các bước.
• Tính hiệu quả: Tính hiệu quả được đánh giá dựa trên một số tiêu chuẩn như khối lượng tính toán, không gian và thời gian được sử dụng (khi thực hiện thuật toán trên máy tính).
• Tính tổng quát: Thuật toán phải áp dụng được cho tất cá các bài toán có dạng như mong muốn chứ không phải chỉ áp dụng được cho một số trường hợp riêng lẻ nào đó.
II.1.2. Biểu diễn thuật toán
Để có thể truyền đạt một thuật toán cho người khác hay chuyển thuật toán cho máy tính (thành chương trình điều khiển máy tính), ta phải tìm cách biểu diễn thuật toán. Một cách tiếp cận tự nhiên là sử dụng các ngôn ngữ để biểu diễn thuật toán.
Các ngôn ngữ thường được sử dụng để biểu diễn thuật toán:
77
Bài giảng tin học đại cương
• Ngôn ngữ tự nhiên
• Ngôn ngữ lưu đồ(sơ đồ khối)
• Ngôn ngữ tựa ngôn ngữ lập trình (mã giả)
• Ngôn ngữ lập trình
Trong cách biểu diễn thuật toán theo ngôn ngữ tự nhiên người ta sử dụng một loại ngôn ngữ tự nhiên để liệt kê các bước của thuật toán. Cách này không yêu cầu người viết thuật toán cũng như người đọc thuật toán phải chuẩn bị một số kiến thức đặc biệt như đối với cách biểu diễn bằng lưu đồ hay mã giả. Tuy nhiên cách biểu diễn theo ngôn ngữ tự nhiên thường dài dòng, không làm nổi bật được cấu trúc của thuật toán. Trong một số trường hợp việc viết một số bước thực hiện trong thuật toán theo ngôn ngữ tự nhiên tỏ ra không hề dễ dàng và khó hiểu.
Ví dụ: Tìm giá trị lớn nhất của một dãy số nguyên có N số
- Đầu vào: số số nguyên dương N và N số nguyên a1, a2,…, aN
- Đầu ra: số nguyên lớn nhất của dãy ak, k trong khoảng [1…N]
Ý tưởng
− Khởi tạo giá trị Max = a1
− Lần lượt so sánh Max với i=2, 3,…, N, nếu ai > Max ta gán giá trị mới cho Max.
Thuật toán
B1: Nhập dãy số ai . B2: Max ← a1.
B3: Nếu i > N, thuật toán kết thúc và Max là giá trị lớn nhất của dãy cần tìm B4: Nếu ai > Max, gán ai cho Max.
B5: Tăng i lên 1 đơn vị. B6: Quay lên b4. B7: Kết thúc.
Cách sử dụng lưu đồ cũng như sử dụng giả mã tỏ ra khá thuật lợi trong việc viết cũng như đọc thuật toán. Thông thường người ta sử dụng 3 hình thức biểu diễn thuật toán: ngôn ngữ tự nhiên, lưu đồ, mã giả. Trong phần này sẽ giới thiệu cách biểu diễn thuật toán bằng lưu đồ và mã giả.
II.1.2.1. Ngôn ngữ lưu đồ
Ngôn ngữ lưu đồ hay sơ đồ khối là một công cụ rất trực quan để diễn đạt các thuật toán. Biểu diễn bằng lưu đồ sẽ giúp ta có được một cái nhìn tổng quan về toàn cảnh của quá trình xử lý theo thuật toán.
Lưu đồ là một hệ thống các nút có hình dạng khác nhau, thể hiện các chức năng khác nhau và được nối với nhau bởi các cung. Lưu đồ được tạo thành từ 4 thành phần chủ yếu sau đây:
a. Nút giới hạn:
78
Bài giảng tin học đại cương
Được biểu diễn bởi hình oovan có ghi chữ bên trong như:
Các nút trên còn được gọi là nút đầu và nút cuối của lưu đồ. b. Nút thao tác:
Là một hình chữ nhật có ghi các lệnh cần thực hiện. Ví dụ:
c. Nút điều kiện:
Thường là một hình thoi có ghi điều kiện cần kiểm tra. Trong các cung nối với nút này có 2 cung ra chỉ hướng đi theo 2 trường hợp: điều kiện đúng và điều kiện sai.
Ví dụ:
d. Cung:
Là các đường nối từ nút này đến nút khác của lưu đồ.
Hoạt động của thuật toán theo lưu đồ được bắt đầu từ nút đầu tiên. Sau khi thực hiện các thao tác hoặc kiểm tra điều kiện ở mỗi nút thì bộ xử lý sẽ theo một cung đến một nút khác. Quá trình thực hiện thuật toán sẽ dừng khi gặp nút kết thúc hay nút cuối.
Ví dụ:
1: Tìm giá trị lớn nhất của một dãy số nguyên có N số
- Đầu vào: số số nguyên dương N và N số nguyên a1, a2,…, aN
- Đầu ra: số nguyên lớn nhất của dãy ak, k trong khoảng [1…N]
Ý tưởng
− Khởi tạo giá trị Max = a1
79
BẮT ĐẦU KẾT THÚC
Tăng k
a<b
Bài giảng tin học đại cương
− Lần lượt so sánh Max với i=2, 3,…, N, nếu ai > Max ta gán giá trị mới cho Max.
Thuật toán
B1: Nhập dãy số ai . B2: Max ← a1.
B3: Nếu i > N, thuật toán kết thúc và Max là giá trị lớn nhất của dãy cần tìm B4: Nếu ai > Max, gán ai cho Max.
B5: Tăng i lên 1 đơn vị. B6: Quay lên b4. B7: Kết thúc.
Vì thuật toán là chỉ ra dãy thao tác và trình tự thao tác để đạt mục đích và dùng cho người dùng con người, nên ngoài cách liệt kê trên, người ta có thể dùng sơ đồ khối để minh hoạ (biểu diễn). Với thuật toán trên, cách biểu diễn theo sơ đồ khối như sau:
Max ← a1 i ← 2 i > N ai> Max Max ← ai i ← i + 1 S Đ Đ S Hiển thị Max và kết thúc Nhập N và dãy các số nguyên ai Qui ước:
- Hình thoi biểu diễn thao tác so sánh
- Hình chữ nhật thể hiện 1 thao tác tính toán đơn giản hay phức tạp - Hình ô van thể hiện thao tác bắt đầu hay kết thúc.
2: Sắp xếp bằng phương pháp tráo đổi (Exchange Sort)
− Đầu vào: Dãy A gồm N số nguyên a1, a2,…, aN
− Đầu ra: Dãy A dược sắp lại theo thứ tự không giảm
Ý tưởng
Bài giảng tin học đại cương
− Với mỗi cặp số liên tiếp trong dãy , nếu số trước không lớn hơn số sau ta đổi chỗ chúng cho nhau.
− Việc đó được lặp cho đến khi không có sự đổi chỗ nào cho nhau.
Thuật toán
B1: Nhập số N và dãy số a1,a2,…,aN
B2: M N.
B3: Nếu M < 2 thì thuật toán kết thúc và hiển thị dãy đó. B4: M M – 1, i 0.
B5: Tăng i lên 1 đơn vị.
B6: Nếu i > M thì quay lại bước 3.
B7: Nếu ai > ai+1 thì tráo đổi hai số đó cho nhau . B8: Quay lên bước 5.
Chú ý:
− Thuật toán này tạo ra sau mỗi lượt sắp một phần tử đúng vị trí và phần tử này không còn tham gia vào quá trình sắp nữa. Nó giống như bọt nước nổi lên mặt nước: bóng nhẹ sẽ được đẩy dấn lên trên. Cũng chính vì thế mà sắp xếp tráo đổi còn có tên “nổi bọt” (Bubble Sort).
− Quá trình được lặp lại với dãy sau khi đã bỏ phần tử cuối dãy, do vậy lúc đầu M được gán với giá trị N và dừng khi M < 2.
− Trong thuật toán trên, i được khởi tạo giá trị 0 và tiến tới M + 1 Với thuật toán trên, cách biểu diễn theo sơ đồ khối như sau:
Bài giảng tin học đại cương M ← N M < 2 i > M ai↔ ai+1 S Đ S S M ← M – 1 i ← 0 i ← i + 1 ai> ai+1 Đ Đ Kết thúc, dãy đã sắp xếp xong Nhập N và N số ai II.1.2.2. Mã giả
Việc sử dụng lưu đồ sẽ rất cồng kềnh đối với các thuật toán phức tạp. Vì vậy người ta còn viết các thuật toán theo một ngôn ngữ tựa ngôn ngữ lập trình được gọi là mã giả. Trong mã giả ta sử dụng các mệnh đề có cấu trúc chuẩn hóa và vẫn dùng ngôn ngữ tự nhiên. Cách viết thuật toán bằng mã giả tỏ ra tiện lợi, đơn giản, và dễ hiểu.
Trong mã giả ta còn sử dụng cả các ký hiệu toán học, các biến và đôi khi cả cấu trúc kiểu thủ tục. Cấu trúc thuật toán kiểu thủ tục thường được sử dụng trình bày các thuật toán đệ quy hay các thuật toán phức tạp cần phải được trình bày thành nhiều cấp độ.
Cùng với việc sử dụng các biến, trong thuật toán rất thường gặp một phát biểu hành động đặt (hay gán) một giá trị cho một biến. Ví dụ: hành động tăng biến i lên 1 có thể được viết như sau:
i:=i+1 Hay
i i + 1
Các cấu trúc thường gặp trong mã giả gồm: - Cấu trúc chọn:
if(điều kiện) then (hành động) và
if(điều kiện) then (hành động)
Bài giảng tin học đại cương
else (hành động) - Cấu trúc lặp:
while (điều kiện) do (hành động) hoặc
repeat
(hành động)
until (điều kiện) hoặc
for (biến):= (giá trị đầu) to (giá trị cuối) do (hành động) hoặc
for (biến):= (giá trị đầu) downto (giá trị cuối) do (hành động)
- Cấu trúc nhảy goto:
goto nhãn x;
Ví dụ:
II.1.3. Thuật toán đệ qui
Thuật giải đệ qui là một trong những sự mở rộng của khái niệm thuật toán. Như đã biết, một thuật toán được đòi hỏi phải thỏa mãn các tính chất:
- Tính xác định - Tính dừng - Tính đúng
Tuy nhiên có những trường hợp việc tìm ra một thuật toán có những tính chất đòi hỏi như trên rất khó khăn nhưng có cách giải có thể vi phạm các tính chất thuật toán nhưng lại khá đơn giản và được chấp nhận. Ví dụ trong những trường hợp bài toán có thể được phân tích và đưa tới việc giải một bài toán cùng loại nhưng cấp độ thấp hơn, chẳng hạn độ lớn dữ liệu nhập nhỏ hơn, giá trị cần tính toán nhỏ hơn… Ta cũng thường thấy những định nghĩa về những đối tượng, những khái niệm dựa trên chính những đối tượng, những khái niệm đó như ví dụ dưới đây:
Ví dụ. Định nghĩa giai thừa
Giai thừa của một số tự nhiên n, ký hiệu là n!, được định nghĩa bằng cách quy nạp như sau: 0!=1,
n!=(n-1)!*n, với mọi n>0
Bài giảng tin học đại cương
Thuật toán để giải bài toán trong những trường hợp như nêu trên thường được dựa trên chính nó, tức là trong các bước của thuật toán có thể có trường hợp thực hiện lại thuật toán đó (nhưng thường với dữ liệu nhập có độ lớn thấp hơn). Những thuật toán loại này gọi là “thuật toán đệ qui”.
Thuật toán đệ qui tính giai thừa của một số tự nhiên:
Input: số tự nhiên n Output: F(n)=n! Thuật giải: 1. F:=1; 2. If n>0 then F:=F(n-1)*n; 3. Output F.
Đối với thuật toán đệ qui chúng ta cần lưu ý một số điểm sau đây:
1. Trong thuật toán đệ qui thương gồm 2 phần: phần cơ sở và phần qui nạp:
- Phần cơ sở nằm trong các trường hợp không cần thực hiện lại thuật toán (hay không có yêu cầu gọi đệ qui).
- Phần đệ qui là phần trong thuật toán có yêu cầu gọi đệ qui, tức là yêu cầu thực hiện lại thuật toán. Trong phần đề qui, yêu cầu gọi đệ qui thường được đặt trong một điều kiện kiểm tra việc gọi đệ qui.
2. Về mặt cài đặt, nếu như có sử dụng biến cục bộ trong thủ tục hay hàm đệ qui thì các biến này được tạo ra và được đặt trong vùng nhớ “STACK”. Do đó quá trình gọi đệ qui dễ gây ra tình trạng tràn STACK. Trong nhiều trường hợp có thể viết lại thuật toán đệ qui dưới dạng lặp.
II.1.4. Một số thuật toán thông dụng II.1.4.1. Thuật toán số học
Thuật toán kiểm tra số nguyên tố
Vấn đề: Cho một số nguyên dương p. Làm thế nào để biết được p có phải số nguyên tố hay không?
Cách đơn giản nhất để biết p có phải số nguyên tố hay không là dựa vào định nghĩa số nguyên tố. Trước hết ta xem xét điều kiện p ≠ 1. Nếu p=1 thì p không nguyên tố. Nếu đúng là p ≠1 thì tiếp tục kiểm tra xem trong các số từ 2 đến p-1 có ước số của p hay không? Nếu có p không nguyên tố; ngược lại p nguyên tố.
Thuật toán:
Nhập: p nguyên dương
Xuất: kết luận về tính nguyên tố của p
Bài giảng tin học đại cương
Thuật toán:
1. if p=1 then begin
Xuất: p không nguyên tố; Dừng thuật toán;
end
2. flag:=TRUE (gán cho cờ hiệu “flag” giá trị TRUE) 3. for k:=2 to p-1 do
if (k là ước số của p) then begin flag:=FALSE; break; (ngắt vòng lặp FOR) end 4. if flag=TRUE then Xuất: p là số nguyên tố else
Xuất: p không là số nguyên tố
Thuật toán …
II.1.4.2. Thuật toán về dãy
Tìm phần tử lớn nhất trong một dãy hữu hạn