Tải bản đầy đủ (.pdf) (20 trang)

Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

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 (201.17 KB, 20 trang )

Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Mở đầu về thiết kế, đánh giá
thuật toán và kiến thức bổ
trợ
Bởi:
Đại Học Phương Đông

Khái niệm thuật toán
Khái niệm về thuật toán
Thuật toán (algorithm) là một trong những khái niệm quan trọng trong lĩnh vực tin học.
Thuật ngữ thuật toán được xuất phát từ nhà toán học Arập Abu Ja’far Mohammedibn
Musa al Khowarizmi (khoảng năm 825).
Tuy nhiên lúc bấy giờ và trong nhiều thế kỷ sau, nó không mang nội dung như ngày nay
chúng ta quan niệm. Thuật toán nổi tiếng nhất có từ thời cổ Hy lạp là thuật toán Euclid,
thuật toán tìm ước chung lớn nhất của hai số nguyên. Có thể mô tả thuật toán đó như
sau:
ThuậttoánEuclid.
Input: m, n nguyên dương
Output: g (ước chung lớn nhất của m và n)
Phương pháp:
Bước 1: Tìm r, phần dư của m cho n
Bước 2: Nếu r = 0, thì g:=n (gán giá trị của n cho g),và dừng lại. Trong trường
hợp ngược lại (r≠0), thì m:=n; n:=r và quay lại bước 1.
Chúng ta có thể quan niệm các bước cần thực hiện để làm một món ăn, được mô tả trong
các sách dạy chế biến món ăn, là một thuật toán. Cũng có thể xem các bước cần tiến
1/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ


hành để gấp đồ chơi bằng giấy ,được trình bày trong sách dạy gấp đồ chơi bằng giấy là
một thuật toán. Phương pháp cộng nhân các số nguuyên, chúng ta đã được học
ở cấp I cũng là các thuật toán.
Vì vậy ta có định nghĩa không hình thức về thuật toán như sau:
Thuật toán là một dãy hữu hạn các bước, mỗi bước mô tả chính xác các phép toán,
hoặc hành động cần thực hiện ... để cho ta lời giải của bài toán.
Các yêu cầu về thuật toán
Định nghĩa trên về thuật toán tất nhiên còn chứa nhiều điều chưa rõ ràng. Để hiểu đầy
đủ ý nghĩa của khái niệm thuật toán, chúng ta đưa ra 5 đặc trưng sau đây của thuật toán.
Input
Mỗi thuật toán đều có một số (có thể bằng không) các dữ liệu vào (input). Đó là các giá
trị cần đưa vào khi thuật toán bắt đầu làm việc. Các dữ liệu này cần được lấy từ các tập
hợp giá trị cụ thể nào đó. Chẳng hạn, trong thuật toán Euclid ở trên, các số m và n là các
dữ liệu lấy từ tập các số nguyên dương.
Output
Mỗi thuật toán cần có một hoặc nhiều dữ liệu ra (output). Đó là các giá trị có quan hệ
hoàn toàn xác định với các dữ liệu vào, và là kết quả của sự thực hiện thuật toán. Trong
thuật toán Euclid, có một dữ liệu ra đó là ƯSCLN g, khi thuật toán dừng lại (trường hợp
r=0) thì giá trị của g là ước chung lớn nhất của m và n.
Tính xác định
Ở mỗi bước, các bước thao tác phải hết sức rõ ràng, không gây nên sự nhập nhằng. Nói
rõ hơn là trong cùng một điều kiện hai bộ xử lý cùng thực hiện một thuật toán phải cho
cùng một kết quả như nhau. Nếu biểu diễn thuật toán bằng phương pháp thông thường
không có gì đảm bảo được người đọc hiểu đúng ý của người viết thuật toán. Để đảm bảo
đòi hỏi này, thuật toán cần được mô tả trong các ngôn ngữ lập trình (ngôn ngữ máy, hợp
ngữ hoặc ngôn ngữ bậc cao như Pascal...). Trong các ngôn ngữ này các mệnh đề được
tạo theo các qui tắc cú pháp nghiêm ngặt và chỉ có một nghĩa duy nhất.
Tính khả thi/đa năng
Tất cả các phép toán có mặt trong thuật toán phải đủ đơn giản . Điều đó có nghĩa là, các
phép toán phải sao cho, ít nhất về nguyên tắc có thể thực hiện bởi con người chỉ bằng

2/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

giấy trắng và bút chì trong một khoảng thời gian hữu hạn. Chẳng hạn, trong thuật toán
Euclid ta chỉ cần thực hiện các phép chia các số nguyên, các phép gán và các phép so
sánh r=0 hay r ≠ 0. Điều quan trọng nữa là thuật toán phải có tính đa năng làm việc được
với tất cả các tập hợp dữ liệu có thể của đầu vào.
Tính dừng
Với mọi bộ dữ liệu vào thoả mãn các điều kiện của dữ liệu vào (tức là được lấy ra từ các
tập của dữ liệu vào), thuật toán phải dừng lại sau một số hữu hạn bước thực hiện.
Thuật toán Euclid thoả mãn điều kiện này. Bởi vì giá trị của r luôn nhỏ hơn n (khi thực
hiện bước 1), nếu r <>0 thì giá trị của n ở bước i (ký hiệu là ni) sẽ là giá trị của ri-1 ở
bước i-1, ta phải có bất đẳng thức n>r =n1>r1 = n2 > r2. Dãy số nguyên dương này giảm
dần và cần phải kết thúc ở 0, do đó sau một số hữu hạn bước nào đó giá trị của r phải =
0 và thuật toán phải dừng lại.
Với một vấn đề đặt ra, có thể có một hoặc nhiều thuật toán giải. Một vấn đề có thuật toán
giải gọi là vấn đề giải được (bằng thuật toán). Chẳng hạn, tìm nghiệm của hệ phương
trình tuyến tính là vấn đề giải được. Một vấn đề không tồn tại thuật toán gọi là vấn đề
không giải được (bằng thuật toán). Một trong những thành tựu suất xắc nhất của toán
học thế kỷ 20 là đã tìm ra những vấn đề không giải được bằng thuật toán. Chẳng hạn
thuật toán chắc thắng cho người thứ hai của cờ ca rô hoặc thuật toán xác định xem một
máy Turing có dừng lại sau n bước không, đềulà những vấn đề không tồn tại thuật toán
giải được.

Thiết kế thuật toán
Để giải một bài toán trên máy tính điện tử (MTĐT), điều trước tiên là chúng ta phải có
thuật toán. Một câu hỏi đặt ra là làm thế nào để tìm ra được thuật toán cho một bài toán
đã đặt ra- Lớp các bài toán được đặt ra từ các ngành khoa học kỹ thuật, từ các lĩnh vực

hoạt động của con người là hết sức phong phú và đa dạng. Các thuật toán giải các lớp
bài toán khác nhau cũng rất khác nhau. Tuy nhiên, có một số kỹ thuật thiết kế thuật toán
chung như: Chia để trị (divide-and-conque), phương pháp tham ăn (greedy method), qui
hoạch động (dynamic programming)... Việc nắm được các chiến lược thiết kế thuật toán
này là hết sức quan trọng và cần thiết vì nó giúp cho ta dễ tìm ra các thuật toán mới cho
các bài toán mới được đưa ra.

Tính đúng đắn của thuật toán
Khi một thuật toán được làm ra, ta cần phải chứng minh rằng, thuật toán khi được thực
hiện sẽ cho ta kết quả đúng với mọi dữ liệu vào hợp lệ. Điều này gọi là chứng minh tính
đúng đắn của thuật toán. Việc chứng minh tính đúng đắn của thuật toán là một công việc

3/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

không dễ dàng. Trong nhiều trường hợp, nó đòi hỏi ta phải có trình độ và khả năng tư
duy toán học tốt.
Sau đây ta sẽ chỉ ra rằng, khi thực hiện thuật toán Euclid, g sẽ là ước chung lớn nhất
của hai số nguyên dương bất kỳ m, n. Thật vậy, khi thực hiện bước 1, ta có m = qn + r,
trong đó q là số nguyên nào đó. Nếu r = 0 thì n là ước của m và hiển nhiên n (do đó g)
là ước chung lớn nhất của m và n. Nếu r 0 thì một ước chung bất kỳ của m và n cũng là
ước chung của n và r (vì r=m-qn). Ngược lại một ước chung bất kỳ của n và r cũng là
ước chung của m và n (vì m = qn + r). Do đó ước chung lớn nhất của n và r cũng là ước
chung lớn nhất của ma và n. Vì vậy, khi thực hiện lặp lại bước 1, với sự thay đổi giá trị
của m bởi n, và sự thay đổi giá trị của n bởi r, cho tới khi r=0 ta nhận được giá trị của g
là ước chung lớn nhất của các giá trị m và n ban đầu.

Phân tích thuật toán

Giả sử, với một số bài toán nào đó chúng ta có một số thuật toán giải. Một câu hỏi mới
xuất hiện là, chúng ta cần chọn thuật toán nào trong số các thuật toán đó để áp dụng.
Việc phân tích thuật toán, đánh giá độ phức tạp của thuật toán là nội dung của phần dưới
đây sẽ giải quyết vấn đề này.

Đánh giá hiệu quả của thuật toán
Khi giải một vấn đề, chúng ta cần chọn trong số các thuật toán, một thuật toán mà chúng
ta cho là “tốt” nhất .Vậy ta cần lựa chọn thuật toán dựa trên cơ sở nào- Thông thường ta
dựa trên hai tiêu chuẩn sau đây:
• Thuật toán đơn giản, dễ hiểu, dễ cài đặt (dễ viết chương trình)
• Thuật toán sử dụng tiết kiệm nhất các nguồn tài nguyên của máy tính, và đặc
biệt chạy nhanh nhất có thể được.
Khi ta viết một chương trình chỉ để sử dụng một số ít lần, và cái giá của thời gian viết
chương trình vượt xa cái giá của chạy chương trình thì tiêu chuẩn (1) là quan trọng nhất.
Nhưng có trường hợp ta cần viết các chương trình (hoặc thủ tục, hàm) để sử dụng nhiều
lần, cho nhiều người sử dụng, khi đó giá của thời gian chạy chương trình sẽ vượt xa giá
viết nó. Chẳng hạn, các thủ tục sắp xếp, tìm kiếm được sử dụng rất nhiều lần, bởi rất
nhiều người trong các bài toán khác nhau. Trong trường hợp này ta cần dựa trên tiêu
chuẩn 2. Ta sẽ cài đặt thuật táon có thể sẽ rất phức tạp, miễn là chương trình nhận được
chạy nhanh hơn so với các chương trình khác.
Tiêu chuẩn 2 được xem là tínhhiệuquảcủa thuật toán. Tính hiệu quả của thuật toán bao
gồm hai nhân tố cơ bản:

4/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Dung lượng không gian nhớ cần thiết để lưu giữ các giữ liệu vào, các kết quả tính toán
trung gian và các kết quả của thuật toán.

Thời gian cần thiết để thực hiện thuật toán (ta gọi là thời gian chạy). Chúng ta chỉ quan
tâm đến thời gian thực hiện thuậ toán, có nghĩa là ta nói đến đánh giá thời gian thực
hiện. Một thuật toán có hiệu quả được xem là thuật toán có thời gian chạy ít hơn so với
các thuật toán khác.

Các phương pháp biểu diễn thuật toán
Có nhiều phương pháp biểu diễn thuật toán .Có thể biểu diễn thuật toán bằng danh sách
các bước, các bước được diễn đạt bằng ngôn ngữ thông thường và các ký hiệu toán học.
Có thể biểu diễn thuật toán bằng sơ đồ khối. Tuy nhiên, để đảm bảo tính xác định của
thuật toán như đã trình bày trên, thuật toán cần được viết trên các ngôn ngữ lập trình.
Một chương trình là sự biểu diễn của một thuật toán trong ngôn ngữ lập trình đã chọn.
Thông thường ta dùng ngôn ngữ lập trình Pascal, một ngôn ngữ thường được chọn để
trình bày các thuật toán trong sách báo.
Ngôn ngữ thuật toán là ngôn ngữ dùng để miêu tả thuật toán .Thông thường ngôn ngữ
thuật toán bao gồm ba loại:
+ Ngôn ngữ liệt kê từng bước;
+ Sơ đồ khối;
+ Ngôn ngữ lập trình;
Phương pháp liệt kê từng bước
Ngôn ngữ liệt kê từng bước nội dung như sau:
Thuật toán: Tên thuật toán và chức năng.
Vào: Dữ liệu vào với tên kiểu.
Ra: Các dữ liệu ra với tên kiểu.
Biến phụ (nếu có) gồm tên kiểu.
Hành động là các thao tác với các lệnh có nhãn là các số tự nhiên.
Để giải phương trình bậc hai ax2 + bx +c = 0, ta có thể mô tả thuật toán bằng
ngôn ngữ liệt kê như sau:
5/20



Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Bước 1: Xác định các hệ số a, b, c.
Bước 2: Kiểm tra xem các hệ số a, b, c có khác 0 hay không- Nếu a=0 quay lại thực hiện
bước 1.
Bước 3: Tính biểu thức Δ= b2 – 4*a*c.
Bước 4: Nếu Δ <0 thông báo phương trình vô nghiệm và chuyển sang bước 8. Bước 5:
Nếu Δ=0, tính x1=x2= 2 −∗ba và chuyển sang bước 7.
Bước 6: Tính x1=
nghiệm x1, x2.

− b + √Δ
2a

, x2=

− b − √Δ
2a

và chuyển sang bước 7. Bước 7: Thông báo các

Bước 8: Kết thúc thuật toán.
Phương pháp sơ đồ
Phương pháp dùng sơ đồ khối mô tả thuật toán là dùng mô tả theo sơ đồ trên mặt
phẳng các bước của thuật toán. Sơ đồ khối có ưu điểm là rất trực giác dễ bao quát.
Để mô tả thuật toán bằng sơ đồ khối ta cần dựa vào các nút sau đây:
Nútthaotác:Biểu diễn bằng hình chữ nhật,

Nútđiềukhiển:Được biểu diễn bằng hình thoi, trong đó ghi điều kiện cần kiểm tra trong
quá trình tính toán.


6/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Nútkhởiđầu,kếtthúc:Thường được biểu diễn bằng hình
tròn thể hiện sự bắt đầu hay kết thúc quá trình.
Cung:Đoạnnối từ nút này đến nút khác và có mũi tên chỉ hướng.

Một số cấu trúc dữ liệu cơ bản
Danh sách
Danh sách là một tập sắp thứ tự các phần tử cùng một kiểu. Đối với danh sách, người ta
có một số thao tác: Tìm một phần tử trong danh sách, chèn một phần tử vào danh sách,
7/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

xoá một phần tử khỏi danh sách, sắp xếp lại các phần tử trong danh sách theo một trật
tự nào đó v.v...
Các phương pháp biểu diễn danh sách trong máy tính:
- Mảng một chiều
- Danh sách nối đơn
- Danh sách nối kép
- Danh sách nối vòng một hướng
- Danh sách nối vòng hai hướng
Các phép toán cơ bản trên danh sách
Để thiết lập kiểu dữ liệu trừu tượng danh sách (hay ngắn gọn là danh sách) ta phải định
nghĩa các phép toán trên danh sách. Và như chúng ta sẽ thấy trong toàn bộ giáo trình,

khôngc ó một tập hợp các phép toán nào thích hợp cho mọi ứng dụng (application). Vì
vậy ở đây ta sẽ định nghĩa một số phép toán cơ bản nhất trên danh sách. Để thuận tiện
cho việc định nghĩa ta giả sử rằng danh sách gồm các phần tử có kiểu là kiểu phần tử
(elementType); vị trí của các phần tử trong danh sách có kiểu là kiểu vị trí và vị trí sau
phần tử cuối cùng trong danh sách L là ENDLIST(L). Cần nhấn mạnh rằng khái niệm
vị trí (position) là do ta định nghĩa, nó không phải là giá trị của các phần tử trong danh
sách. Vị trí có thể là đồng nhất với vị trí lưu trữ phần tử hoặc không.
Các phép toán được định nghĩa trên danh sách là:
INSERT_LIST(x,p,L):xen phần tử x ( kiểu ElementType ) tại vị trí p (kiểu
position) trong danh sách L. Tức là nếu danh sách là a1, a2, . , ap-1, ap,.. , an thì sau khi
xen ta có kết quả a1, a2. . . ap-1, x, ap, . . . , an. Nếu vị trí p không tồn tại trong danh
sách thì phép toán không được xác định.
LOCATE(x,L):thực hiện việc định vị phần tử có nội dung x đầu tiên trong danh sách
L. Locate trả kết quả là vị trí (kiểu position) của phần tử x trong danh sách. Nếu x không
có trong danh sách thì vị trí sau phần tử cuối cùng của danh sách được trả về, tức là
ENDLIST(L).
- RETRIEVE(p,L):lấy giá trị của phần tử ở vị trí p (kiểu position) của danh sách L; nếu
vị trí p không có trong danh sách thì kết quả không xác định (có thể thông báo lỗi).

8/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

- DELETE_LIST(p,L):chương trình con thực hiện việc xoá phần tử ở vị trí p (kiểu
position) của danh sách. Nếu vị trí p không có trong danh sách thì phép toán không được
định nghĩa và danh sách L sẽ không thay đổi
- NEXT(p,L):cho kết quả là vị trí của phần tử (kiểu position) đi sau phần tử p; nếu p là
phần tử cuối cùng trong danh sách L thì NEXT(p,L) cho kết quả là
ENDLIST(L):Next không xác định nếu p không phải là vị trí của một phần tử trong

danh sách.
- PREVIOUS(p,L):cho kết quả là vị trí của phần tử đứng trước phần tử p trong danh
sách. Nếu p là phần tử đầu tiên trong danh sách thì Previous(p,L) không xác định.
Previous cũng không xác định trong trường hợp p không phải là vị trí của phần tử nào
trong danh sách.
- FIRST(L):cho kết quả là vị trí của phần tử đầu tiên trong danh sách. Nếu danh sách
rỗng thì ENDLIST(L) được trả về.
- EMPTY_LIST(L):cho kết quả TRUE nếu danh sách có rỗng, ngược lại nó cho giá trị
FALSE.
- MAKENULL_LIST(L):khởi tạo một danh sách L rỗng.
- Trong thiết kế các giải thuật sau này chúng ta dùng các phép toán trừu tượng đã được
định nghĩa ở đây như là các phép toán nguyên thủy.
Đồ thị
Các định nghĩa
Một đồ thị G bao gồm một tập hợp V các đỉnh và một tập hợp E các cung, ký hiệu
G=(V,E). Các đỉnh còn được gọi là nút (node) hay điểm (point). Các cung nối giữa
hai đỉnh, hai đỉnh này có thể trùng nhau. Hai đỉnh có cung nối nhau gọi là hai đỉnh kề
(adjacency). Một cung nối giữa hai đỉnh v, w có thể coi như là một cặp điểm (v,w). Nếu
cặp này có thứ tự thì ta có cung có thứ tự, ngược lại thì cung không có thứ tự. Nếu các
cung trong đồ thị G có thứ tự thì G gọi là đồ thị có hướng (directed graph). Nếu các cung
trong đồ thị G không có thứ tự thì đồ thị G là đồ thị vô hướng (undirected graph).
Biểu diễn đồ thị
- Biểu diễn đồ thị bằng ma trận kề
- Biểu diễn đồ thị bằng danh sách các đỉnh kề:

9/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ


Các phép duyệt đồ thị
- Duyệt theo chiều sâu (depth-first search)
- Duyệt theo chiều rộng (breadth-first search)
Cây
Các thuật ngữ cơ bản trên cây
Cây là một tập hợp các phần tử gọi là nút (nodes) trong đó có một nút được phân biệt
gọi là nút gốc (root). Trên tập hợp các nút này có một quan hệ, gọi là mối quan hệ
cha-con(parenthood), để xác định hệ thống cấu trúc trên các nút. Mỗi nút, trừ nút
gốc, có duy nhất một nút cha. Một nút có thể có nhiều nút con hoặc không có nút
con nào. Mỗi nút biểu diễn một phần tử trong tập hợp đang xét và nó có thể có một
kiểu nào đó bất kỳ, thường ta biểu diễn nút bằng một kí tự, một chuỗi hoặc một
số ghi trong vòng tròn. Mối quanhệchaconđược biểu diễn theo qui ước nútchaởdòng
trênnútconởdòngdướivàđượcnốibởimộtđoạnthẳng. Một cách hình thức ta có thể định
nghĩa cây một cách đệ qui như sau:
Định nghĩa
Một nút đơn độc là một cây. Nút này cũng chính là nút gốc của cây.
Giả sử ta có n là một nút đơn độc và k cây T1,.., Tk với các nút gốc tương ứng là n1,..,
nk thì có thể xây dựng một cây mới bằng cách cho nút n là cha của các nút n1,.., nk. Cây
mới này có nút gốc là nút n và các cây T1,.., Tk được gọi là các cây con. Tập rỗng cũng
được coi là một cây và gọi là cây rỗng kí hiệu.
Xét mục lục của một quyển sách. Mục lục này có thể xem là một cây
Cây m ụ c l ụ c m ột qu y ể n sách
Nút gốc là sách, nó có ba cây con có gốc là C1, C2, C3. Cây con thứ 3 có gốc C3 là một
nút đơn độc trong khi đó hai cây con kia (gốc C1 và C2) có các nút con.
Nếu n1,.., nk là một chuỗi các nút trên cây sao cho ni là nút cha của nút ni+1, với
i=1..k-1, thì chuỗi này gọi là một đườngđitrêncây(hay ngắn gọn là đường đi ) từ n1
đến nk. Độdàiđườngđiđược định nghĩa bằng số nút trên đường đi trừ 1. Như vậy độ dài
đường đi từ một nút đến chính nó bằng không.
Nếu có đường đi từ nút a đến nút b thì ta nói a là tiềnbối (ancestor) của b, còn b gọi là
hậuduệ(descendant) của nút a. Rõ ràng một nútvừalàtiềnbối vừalàhậu duệcủachínhnó.

10/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Tiền bối hoặc hậu duệ của một nút khác với chính nó gọi là tiền bối hoặc hậu duệ thực
sự. Trên cây nútgốckhông có tiền bối thực sự. Một nút không có hậu duệ thực sự gọi là
nútlá(leaf). Nút không phải là lá ta còn gọi là núttrung gian(interior). Cây con của một
cây là một nút cùng với tất cả các hậu duệ của nó.
Chiềucaocủamộtnútlà độ dài đường đi lớn nhất từ nút đó tới lá. Chiềucaocủa câylà chiều
cao của nút gốc. Độsâucủamộtnútlà độ dài đường đi từ nút gốc đến nút đó. Các nút có
cùng một độ sâu i ta gọi là các nút có cùng một mức i. Theo định nghĩa này thì nút gốc
ở mức 0, các nút con của nút gốc ở mức 1.
Các thứ tự duyệt cây quan trọng
Duyệt cây là một qui tắc cho phép đi qua lần lượt tất cả các nút của cây mỗi nút đúng
một lần, danh sách liệt kê các nút (tên nút hoặc giá trị chứa bên trong nút) theo thứ
tự đi qua gọi là danh sách duyệt cây. Có ba cách duyệt cây quan trọng: Duyệt tiềntự
(preorder), duyệttrungtự(inorder), duyệt hậutự(posorder). Có thể định nghĩa các phép
duyệt cây tổng quát một cách đệ qui như sau:
- Cây rỗng thì danh sách duyệt cây là rỗng và nó được coi là biểu thức duyệt tiền tự,
trung tự, hậu tự của cây.
- Cây chỉ có một nút thì danh sách duyệt cây gồm chỉ một nút đó và nó được coi là biểu
thức duyệt tiền tự, trung tự, hậu tự của cây.
- Ngược lại: giả sử cây T có nút gốc là n và có các cây con là T1,..,Tn thì:
+ Biểu thức duyệt tiền tự của cây T là liệt kê nút n kế tiếp là biểu thức duyệt tiền tự của
các cây T1, T2, .., Tn theo thứ tự đó.
+ Biểu thức duyệt trung tự của cây T là biểu thức duyệt trung tự của cây T1 kế tiếp là
nút n rồi đến biểu thức duyệt trung tự của các cây T2,.., Tn theo thứ tự đó.
+ Biểu thức duyệt hậu tự của cây T là biểu thức duyệt hậu tự của các cây T1, T2,.., Tn
theo thứ tự đó rồi đến nút n.

Cho cây như trong hình

11/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Biểu thức duyệt tiền tự: A B C D E F H K L Trung tự: C B E D F A K H L
Hậu tự: C E F D B K L H A
Các phép toán trên cây
- Hàm PARENT(n,T)cho nút cha của nút n trên cây T, nếu n là nút gốc thì hàm cho giá
trị NULL. Trong cài đặt cụ thể thì NULL là một giá trị nào đó do ta chọn, nó phụ thuộc
vào cấu trúc dữ liệu mà ta dùng để cài đặt cây.
- Hàm LEFTMOST_CHILD(n,T)cho nút con trái nhất của nút n trên cây T, nếu n là lá
thì hàm cho giá trị NULL.
- Hàm RIGHT_SIBLING(n,T)cho nút anh em ruột phải nút n trên cây T, nếu n không
có anh em ruột phải thì hàm cho giá trị NULL.
- Hàm LABEL_NODE(n,T)cho nhãn tại nút n của cây T.
- Hàm ROOT(T)trả ra nút gốc của cây T. Nếu Cây T rỗng thì hàm trả về NULL.
- Hàm CREATEi(v,T1,T2,..,Ti),với i=0..n, thủ tục tạo cây mới có nút gốc là n được
gán nhãn v và có i cây con T1,..,Ti. Nếu n= 0 thì thủ tục tạo cây mới chỉ gồm có 1 nút
đơn độc là n có nhãn v. Chẳng hạn, giả sử ta có hai cây con T1 và T2, ta muốn thiết lập
cây mới với nút gốc có nhãn là v thì lời gọi thủ tục sẽ là CREATE2(v,T1,T2).
Cài đặt cây
- Cài đặt cây bằng mảng
- Biểu diễn cây bằng danh sách các con
- Biểu diễn theo con trái nhất và anh em ruột phải:

12/20



Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Cây nhị phân (Binary Trees)
Cây nhị phân là cây rỗng hoặc là cây mà mỗi nút có tối đa hai nút con. Hơn nữa các nút
con của cây được phân biệt thứ tự rõ ràng, một nút con gọi là nút con trái và một nút con
gọi là nút con phải. Ta qui ước vẽ nút con trái bên trái nút cha và nút con phải bên phải
nút cha, mỗi nút con được nối với nút cha của nó bởi một đoạn thẳng.
Cây tìm kiếm nhị phân (Binary Search Trees)
Cây tìm kiếm nhị phân (TKNP) là cây nhị phân mà khoá tại mỗi nút cây lớn hơn khoá
của tất cả các nút thuộc cây con bên trái và nhỏ hơn khoá của tất cả các nút thuộc cây
con bên phải. Lưu ý: dữ liệu lưu trữ tại mỗi nút có thể rất phức tạp như là một record
chẳng hạn, trong trường hợp này khoá của nút được tính dựa trên một trường nào đó,
ta gọi là trường khoá. Trường khoá phải chứa các giá trị có thể so sánh được, tức là nó
phải lấy giá trị từ một tập hợp có thứ tự.
Tập hợp
Định nghĩa
Tập hợp là một khái niệm cơ bản trong toán học. Tập hợp được dùng để mô hình hoá
hay biểu diễn một nhóm bất kỳ các đối tượng trong thế giới thực cho nên nó đóng vai
trò rất quan trọng trong mô hình hoá cũng như trong thiết kế các giải thuật.
Khái niệm tập hợp cũng như trong toán học , đó là sự tập hợp các thành viên ( members
) hoặc phần tử (elements) . Tất cả các phần tử của tập hợp là khác nhau. Tập hợp có thể
có thứ tự hoặc không có thứ tự, tức là , có thể có quan hệ thứ tự xác định trên các phần
tử của tập hợp hoặc không. Tuy nhiên, trong chương này, chúng ta giả sử rằng các phần
tử của tập hợp có thứ tự tuyến tính, tức là , trên tập hợp S có quan hệ < và = thoả mản
hai tính chấ t:
- Với mọi a,b S thì a- Với mọi a,b ,c S, a Các phép toán cơ bản trên kiểu dữ liệu tập hợp
Cũng như các kiểu dữ liệu trừu tượng khác, các phép toán kết hợp với mô hình tập hợp

sẽ tạo thành một kiểu dữ liệu trừu tượng là rất đa dạng . Tùy theo nhu cầu của các ứng
dụng mà các phép toán khác nhau sẽ được định nghĩa trên tập hợp. Ở đây ta đề cập đến
một số phép toán thường gặp nhất như sau :
- Thủ tục UNION(A,B,C)nhận vào 3 tham số là A,B,C; Thực hiện phép toán lấy hợp
của hai tập A và B và trả ra kết quả là tập hợp C = A ?B.
13/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

- Thủ tục INTERSECTION(A,B,C)nhận vào 3 tham số là A,B,C; Thực hiện phép
toánlấy giao của hai tập A và B và trả ra kết quả là tập hợp C = A ? B.
- Thủ tục DIFFERENCE(A,B,C)nhận vào 3 tham số là A,B,C; Thực hiện phép toán
lấy hợp của hai tập A và B và trả ra kết quả là tập hợp C = A\B
- Hàm MEMBER(x,A)cho kết quả kiểu logic (đúng/sai) tùy theo x có thuộc
A hay không. Nếu x ∈ A thì hàm cho kết quả là 1 (đúng), ngược lại cho kết quả 0 (sai).
- Thủ tục MAKENULLSET(A)tạo tập hợp A tập rỗng
- Thủ tục INSERTSET(x,A)thêm x vào tập hợp A
- Thủ tục DELETESET(x,A)xoá x khỏi tập hợp A
- Thủ tục ASSIGN(A,B)gán A cho B ( tức là B:=A )
- Hàm MIN(A)cho phần tử bé nhất trong tập A
- Hàm EQUAL(A,B)cho kết quả TRUE nếu A=B ngược lại cho kết quả FALSE
Cài đặt tập hợp
- Cài đặt tập hợp bằng vector Bit
- Cài đặt bằng danh sách liên kết

Ngôn ngữ tựa Pascal
Bảng chữ cái và ký tự chủ yếu
Ngôn ngữ tựa Pascal được sử dụng dùng để mô tả các bước của thuật toán. Nó có đặc
điểm là giúp mô tả thuật toán gần gũi với một chương trình máy tính và làm mô tả thuật

toán trở nên chính xác hơn. Dưới đây là liệt kê một số câu lệnh chính được sử dụng để
mô tả thuật toán dùng ngôn ngữ lập trình Pascal:
Ký tự và biểu thức
Các ký tự la tinh: A, a... Z, z. Chữ số: 0…9. Các phép toán số học: +, - , *, /
Các phép toán quan hệ : < , >, =, Giá trị logic: T (true), F (false) Phép toán logic: and,
or, not

14/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Hằng đó là các giá trị cụ thể nào đó
Tên biến: Là một dãy kí tự mà kí tự đầu phải là chữ cái.
Có hai loại biến chính:
Loại integer (biến nguyên).
Var bien: integer; Loại Real (biến thực) .
var bien real;
Biến chỉ số. Ở đây i là các biến nguyên.
Biểu thức là kết hợp các hằng, biến và các phép toán.
Một số câu lệnh chính
Đầu chương trình
program (tên chương trình) .Tên chương trình có cấu trúc giống tên biến .
Program giai_pt;
............................... Các thủ tục và hàm
Câu lệnh Procedure (function). Mô tả thuật toán trong ngôn ngữ phỏng Pascal, được
bắt đầu bằng câu lệnh procedure (function), trong đó ta đặt tên cho thuật toán và mô tả
danh sách biến của thuật toán. Chẳng hạn, câu lệnh
Function max(a,b,c);
Cho biết tên của thuật toán là max và các biến là a, b, c

Procedure move(n,A,B,C);
Cho biết tên thuật toán được mô tả là move với các biến là n, A, B, C;
Các bước của thuật toán được mô tả trong thân thủ tục (hàm) được bắt đầu bởi
Begin và kết thúc bởi end.

15/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Function max(a,b,c); Begin
........ (thân hàm) End;
Procedure move(n,A,B,C); Begin
......... (thân thủ tục)
end;
Câu l ệnh gán
Câu lệnh gán được dùng để gán giá trị cho các biến Vế trái của câu lệnh gán là tên của
biến , còn vế phải là biểu thức của các hằng , biến đã gán giá trị hoặc các hàm đã được
định nghĩa. Ký hiệu := được sử dụng để biểu diễn phép gán.
Variable := exp; Max := a;
x := số lớn nhất trong các số a,b,c…
Khối câu lệnh
Các câu lệnh có thể nhóm lại thành một khối. Để mô tả khối lệnh ta sử dụng Begin và
end
Begin
Câu lệnh 1;
Câu lệnh 2;
.................. Câu lệnh n;
End;
Các câu lệnh trong khối được thực hiện tuần tự. Dưới đây thuật ngữ câu lệnh được dùng

để chỉ chung một câu lệnh cũng như một khối câu lệnh.
(*a là số phần tử lớn nhất trong danh sách L*)
k là số phần tử của danh sách L
Câu lệnh điều kiện.

16/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Câu lệnh đơn giản là
If điều kiện then câu lệnh;
Khi thực hiện câu lệnh, điều kiện sẽ được kiểm tra, nếu nó được thoả mãn thì câu lệnh
sẽ được thực hiện.
Nhiều khi ta cần thực hiện một thao tác nào đó khi điều kiện được thực hiện còn nếu
ngược lại ta phải thực hiện một thao tác khác. Khi đó ta có thể thực hiện câu lệnh phức
tạp hơn sau đây:
If điều kiện then câu lệnh 1
else câu lệnh 2;
Các câu lệnh lặp.
Các câu lệnh sau đây sẽ được sử dụng
For biến := giá trị đầu to giá trị cuối do câu lệnh;
Tại đầu vòng lặp, biến được sẽ gán cho giá trị đầu, nếu giá trị đầu nhỏ hơn hơn hoặc
bằng giá trị cuối và câu lệnh được thực hiện với giá trị này của biến. Tiếp đến giá trị
của biến sẽ tăng lên 1và câu lệnh sẽ được thực hiện với giá trị mới của biến. Quá trình
sẽ được tiếp tục cho đến khi biến bằng giá trị cuối. Sau khi thực hiện câu lệnh với biến
bằng giá trị cuối sẽ chuyển sang thực hiện câu lệnh tiếp theo. Nếu giá trị đầu lớn hơn giá
trị cuối thì không có câu lệnh nào được thực hiện.
Câu lệnh lặp thứ hai được sử dụng là câu lệnh “while” While điều kiện do câu lệnh;
Khi câu lệnh này được sử dụng, điều kiện sẽ được kiểm tra, nếu nó là đúng thì câu lệnh

được thực hiện .Điều đó sẽ tiếp tục cho đến khi điều kiện sai.
Câu lệnh tiếp theo được sử dụng là câu lệnh “repeat”
Repeat câu lệnh
......................
until điều kiện;
Khi câu lệnh này được sử dụng thì câu lệnh trong vòng lặp được thực hiện, điều đó có
thể sẽ dẫn đến sự thay đổi giá trị của các biến trong điều kiện. Nếu điều kiện vẫn là
đúng, thì câu lệnh lại được thực hiện. Điều đó sẽ tiếp diễn cho đến khi điều kiện là đúng.
17/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

Để giải phương trình bậc hai ax2 + bx + c = 0 ta mô tả thuật toán bằng một chương trình
viết trên Pascal như sau:
Program giai_PT; Var
a,b,c, denta, x1, x2 : real; Begin
Clrscr;
Write(‘Nhập hệ số:’); Repeat
Write(‘a:=’);readln(a); Write(‘b:=’);readln(b); Write(‘c:=’);readln(c);
Until a<>0; Denta:=sqr(b)-4*a*c; If denta<0 then
Begin
Write(‘phương trình vô nghiệm’);
Halt; End
Else
Begin
If denta=0 then
Begin
End
Else

Begin
Write(‘phương trình có nghiệm kép x=’,(b/(2*a)));
Exit;
X1:=(-b-sqrt(denta))/(2*a); X2:=(-b+sqrt(denta))/(2*a);
Write(‘phương trình có hai nghiệm phân biệt:’);
Write(‘x1 = ‘ , x1 , ’x2 = ‘,x2); Exit;

18/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

End; End;
Readln; End.

Bài tập chương
Xác định số phép tính so sánh nhiều nhất có thể trong thuật toán của bạn tìm phần tử lớn
nhất của một dãy n số thực cho trước.
Dành cho độc giả.
Xác định số phép tính so sánh nhiều nhất có thể trong thuật toán của bạn để xếp lại một
dãy có n số thực theo thứ tự tăng dần.
Dành cho độc giả.
Xác định số bước thực hiện nhiều nhất có thể trong thuật toán của bạn nhằm xác định
được nhiều nhất có thể các số liên tiếp nhau có tổng dương trong một dãy n số hạng cho
trước.
Dành cho độc giả.
Mô tả các thuật toán của bạn bằng sơ đồ khối:
a) Thuật toán tìm phần tử lớn nhất của một dãy hữu hạn số thực.
b) Thuật toán tìm phần tử bé nhất của một tập con của tập hợp.
c) Thuật toán xếp lại một dãy theo thứ tự tăng dần.

d) Thuật toán tìm một dãy các số liên tiếp nhau (dài nhất có thể) có tổng dương trong
một dãy số thực cho trước.
Dành cho độc giả.
Viết các thuật toán của bạn bằng ngôn ngữ tựa Pascal:
a) Thuật toán tìm phần tử lớn nhất của một dãy hữu hạn số thực.
b) Thuật toán tìm phần tử bé nhất của một tập hợp con của tập hợp.
c) Thuật toán xếp lại một dãy theo thứ tự tăng dần.

19/20


Mở đầu về thiết kế, đánh giá thuật toán và kiến thức bổ trợ

d) Thuật toán tìm một dãy các số liên tiếp nhau (dài nhất có thể) có tổng dương trong
một dãy số thực cho trước.
Dành cho độc giả.

20/20