Giới thiệu về thuật toán
trong tin học
1. Khái niệm thuật toán
Thuật toán là một hệ thống chặt chẽ và rõ ràng các
quy tắc nhằm xác định một dãy các thao tác trên những
đối tượng, sao cho sau một số hữu hạn bước thực hiện các
thao tác ta đạt được mục tiêu định trước.
Để giải các bài toán bằng máy tính chúng ta thường
phải có một quan niệm rộng rãi hơn về thuật toán cụ thể
là lưu ý đến các đặc điểm sau:
a) Không cần xác định toàn bộ lời giải, các thao
tác theo từng bước một cách chính xác, đơn vị và rõ
ràng.Thay vào đó chỉ cần chỉ ra một cách chuyển từ
một bước giải i tới bước giải kế tiếp i+1, và tìm cách
cắt nhỏ bài toán thành các bài toán con, đó chính là
thuật toán đệ quy rất quan trọng để giải các bài toán
tổng quát.
b) Có nhiều bài toán không có cách giải đúng,
hoặc cách giải đúng không thể chấp nhận được do
hạn chế về thời gian chạy và kích thước bộ nhớ.
Nhưng nếu ta chấp nhận kết quả gần đúng thì có thể
tồn tại nhiều cách giải đỡ phức tạp và có hiệu quả
hơn, đó chính là các thuật toán Heuristic để giải các
bài toán gần đúng.
2. Khái niệm bài toán:
Trong phạm vi tin học ta có thể quan niệm bài toán là
một việc nào đó ta muốn máy tính thực hiện. Các bài toán
được cấu tạo bởi 2 thành phần cơ bản Input và Output.
Thuật toán cũng có thể được hiểu là một dãy các thao tác
được sắp xếp theo trình tự xác định sao cho sau khi thực
hiện dãy thao tác ấy, từ Input của bài toán ta nhận được
Output cần tìm.
3. Một số ví dụ:
Bài toán 1:Tìm giá trị lớn nhất của một dãy số nguyên
Xác định bài toán
Input: Số nguyên dương N và dãy N số nguyên
a
1
,a
2
, ,a
N
Output: Giá trị lớn nhất Max của dãy số.
Ý tưởng:
Chọn Max=a
1
Lần lượt với i từ 2 đến N, so sánh a
i
với a
1
, nếu
a
i
>a
1
thì gán Max=a
i
Thuật toán giải được mô tả như sau:
Nhập N>0 và dãy a
1
,a
2
,…,a
N
.
Max a
1
, i 2;
Nếu i > N thì đưa giá trị Max rồi kết thúc;
Nếu a
i
> Max thì Max a
i
i i + 1 rồi quay lại bước 3.
Bài toán 2: Tìm UCLN của hai số nguyên dương m,n.
Xác định bài toán:
Input : 2 số nguyên dương m,n.
Output : UCLN của 2 số.
Ý tưởng 01: UCLN(m,n)=UCLN(m,m-n) (Giả sử m>n)
Thuật toán giải được mô tả như sau:
Nhập 2 số m,n > 0.
Nếu m=n thì đưa ra UCLN(m,n)=m;
Nếu m > n thì m m-n rồi quay lại bước 2.
Nếu n>m thì n n-m rồi quay lại bước 2.
Đưa ra kết quả UCLN khi một trong m hoặc n=0
(Nếu m=0 thì UCLN(m,n)=n còn nếu m≠0 thì
UCLN(m,n)=m)
Ý tưởng 02: UCLN(m,n) = UCLN(n,m mod n)
Thuật toán giải 02 : dành cho bạn đọc.
Bài toán 3: Cho dãy A gồm N số nguyên a
1
,a
2
,…,a
N
.
Sắp xếp các số hạng để dãy A là trở thành dãy không
giảm (tức là số hạng sau luôn lớn hơn hoặc bằng số
hạng trước)
Xác định bài toán:
Input: Dãy A gồm N số nguyên a
1
,a
2
,…,a
N
.
Output: Dãy A đã được sắp xếp trở thành dãy
không giảm
Ý tưởng 01:
Với mỗi cặp số hạng đứng liền kề nhau trong dãy,
nếu số đứng trước lớn hơn số đứng sau thì ta đổi chỗ hai
số cho nhau. Quá trình lặp lại cho đến khi không còn sự
đổi chỗ xảy ra.
Thuật toán giải được mô tả như sau:
Nhập N>0 và dãy a
1
,a
2
,…,a
N
.
M N
Nếu M < 2 thì đưa ra dãy A được sắp xếp rồi kết
thúc.
Nếu M ≥ 2 thì M M-1, i 0
i i+1
Nếu i > M thì quay lại bước 3.
Nếu a
i
> a
i+1
thì tráo đổi vị trí a
i
và a
i+1
Quay lại bước 5.
Ý tưởng 02 :
Chia dãy cần sắp xếp thành 2 phần, lấy thành phần
giữa X làm chuẩn để so sánh.
• Tìm một phần tử A ở dãy trên có giá trị lớn hơn X
• Tìm một phần tử B ở dãy dưới có giá trị nhỏ hơn X
• Hoán vị A và B.
• Tiếp tục như vậy cho đến khi ta đạt được dãy trên
chỉ gồm các phần tử nhỏ hơn X, dãy dưới chỉ gồm
các phần tử lớn hơn X.
• Áp dụng thuật toán trên vào dãy trên và dãy dưới
(đệ quy) cho đến khi không chia được nữa.
Thuật toán giải 02: bạn thử mô tả xem sao, đây coi
như là một bài tập nhỏ cho các bạn yêu thích lập trình.
Bài toán 4: Cho dãy A gồm N số nguyên a
1
,a
2
,…,a
N
và
một số X. Hãy xác định xem giá trị của X có nằm trong
dãy A không? Nếu có thì nằm ở đâu ?
Xác định bài toán:
Input: dãy A gồm N số nguyên a
1
,a
2
,…,a
N
và số X.
Output: X có thuộc A không? Nếu có thì nằm ở vị
trí nào?
Ý tưởng: So sánh từng phần tử của dãy với X. Nếu có
phần tử a
i
= X thì đưa ra thứ tự của phần tử thứ i thỏa a
i
= X.
Thuật toán giải được mô tả như sau :
Nhập N>0 ,dãy a
1
,a
2
,…,a
N
,và số X
i 1.
Nếu i > N thì kết thúc và đưa kết quả
Nếu i < N thì tiếp tục.
Nếu a
i
= X thì kết thúc và đưa ra thứ tự của X là
i .
Nếu a
i
≠ X thì i i + 1 và quay lại bước 5. Vòng
lặp kết thúc khi i > N
4.(nói thêm) Phương pháp tinh chế từng
bước trong lập trình:
1
Ban đầu chương trình được viết bằng những
lời tự nhiên (tiếng Việt chẳng hạn) thể hiện sự
phân tích tổng thể của người lập trình.
Ở từng bước sau, mỗi câu lời được phân tích
ra chi tiết hơn bằng nhiều câu lời khác tương
ứng với sự phân tích một công việc thành
những công việc nhỏ hơn. Mỗi câu lời đó là
một sự đặc tả công việc.
Ta nói ở mỗi bước ta đã tinh chế những câu lời
đó. Sự tinh chế được hướng về phía ngôn ngữ
lập trình mà ta sẽ dùng. Nghĩa là, càng ở
những bước sau, các câu lời tự nhiên càng
được thay nhiều bằng các câu lời của ngôn
ngữ lập trình.
Một câu lời tự nhiên nếu đơn giản thì ta có
thể thay bằng một vài phát biểu, nếu phức
tạp thì ta coi nó như một thủ tục và tiếp tục
tinh chế nó.
Trong qua trình tinh chế đó, ta cần đưa ra
những biểu diến dữ liệu, vì dữ liệu là nguyên
liệu của máy tính. Như vậy cùng với sự tinh
chế các công việc, dữ liệu cũng được tinh
chế, phân rã, hay cấu trúc hóa. Điều này có
nghĩa là sự tinh chế các dặc tả chương trình
và dữ liệu là song song.
Phương pháp tinh chế từng bước là một thể
hiện của tư duy giải quyết vấn đề từ trên
xuống, trong đó sự phát triển của các bước là
hướng về phía ngôn ngữ lập trình được dùng.
Đáy của sự đi xuống trong hoạt động phân
1
Trích từ cuốn “Phương pháp giải các bài toán trong tin học” của Thạc sĩ Trần Đức Huyên (NXBGD
2001)
tích là các phát triển và các mô tả dữ liệu viết
bằng ngôn ngữ lập trình.
Hiểu được phương pháp tinh chế từng bước
sẽ giúp người lập trình có được môt định
hướng thể hiện sự ngăn nắp trên tờ giấy nháp
của mình, tránh khỏi việc phải mò mẫm, thử
đi thử lại nhiều lần các chương trình mang
tính trực giác.