Chương 4 của luận văn trình bày về việc tổng quát hóa một số thuật giải tìm kiếm. Việc tổng quát hóa xuất phát bằng cách xây dựng thuật giải tìm kiếm tổng quát và mở rộng dần sang các thuật giải đặc thù khác như tìm kiếm theo chiều sâu, tìm kiếm theo chiều rộng đến các thuật giải heuristics, thuật giải leo đồi, thuật giải A* Phần còn lại của chương 4 là một số ví dụ việc áp dụng khung thuật giải tìm kiếm này cho từng thuật toán tìm kiếm cụ th ể.
                
              
                                            
                                
            
 
            
                 14 trang
14 trang | 
Chia sẻ: vietpd | Lượt xem: 2820 | Lượt tải: 4 
              
            Bạn đang xem nội dung tài liệu Thiết lập một số thuật giải tìm kiếm, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
53 
Chương 4 
Thiết lập một số thuật giải tìm kiếm 
Chương 4 của luận văn trình bày về việc tổng quát hóa một số thuật giải tìm kiếm. 
Việc tổng quát hóa xuất phát bằng cách xây dựng thuật giải tìm kiếm tổng quát và 
mở rộng dần sang các thuật giải đặc thù khác như tìm kiếm theo chiều sâu, tìm 
kiếm theo chiều rộng … đến các thuật giải heuristics, thuật giải leo đồi, thuật giải 
A* … Phần còn lại của chương 4 là một số ví dụ việc áp dụng khung thuật giải tìm 
kiếm này cho từng thuật toán tìm kiếm cụ thể. 
4.1 Họ thuật giải tìm kiếm 
Bài toán tìm kiếm là một trong những bài toán cơ bản nhưng quan trọng bật nhất 
của khoa học máy tính. Yêu cầu đặt ra của bài toán chỉ đơn giản là tìm một lời giải 
thỏa mãn bài toán bằng cách duyệt qua một số ứng viên trong không gian tìm kiếm. 
Mỗi thứ tự chờ duyệt của các ứng viên trong không gian tìm kiếm này lại trở thành 
mỗi thuật giải khác nhau. Ví dụ thứ tự chờ duyệt phần tử của thuật giải tìm kiếm 
theo chiều sâu theo cơ chế “vào sau ra trước” rõ ràng khác hẳn với thứ tự chờ duyệt 
“vào trước ra trước” của thuật giải tìm kiếm theo chiều rộng. 
54 
Các bài toán tìm kiếm được phân loại như sau: 
- Tìm kiếm không có thông tin: Một thuật giải tìm kiếm không có thông tin 
là thuật giải không tính đến bản chất cụ thể của bài toán. Khi đó, các thuật 
giải dạng này có thể được cài đặt tổng quát, và cùng một cài đặt có thể được 
sử dụng trong một diện rộng các bài toán (do sử dụng trừu tượng hóa). 
Nhược điểm của các thuật giải này là phần lớn các không gian tìm kiếm có 
kích thước cực kì lớn. Thuật giải tìm kiếm không có thông tin được phân loại 
như sau: 
o Tìm kiếm trên danh sách: Có lẽ các thuật giải tìm kiếm trên danh 
sách là loại thuật giải tìm kiếm cơ bản nhất. Mục đích là tìm trong một 
tập hợp một phần tử chứa một khóa có giá trị cho trước. Do đây là 
một bài toán thường gặp trong khoa học máy tính, nên độ phức tạp 
tính toán của các thuật giải này đã được nghiên cứu kỹ càng. Thuật 
giải đơn giản nhất là tìm kiếm tuyến tính. Thuật giải này kiểm tra từng 
phần tử trong danh sách theo thứ tự của danh sách đó. Nó có thời gian 
chạy khá lớn: ( ), trong đó n là số phần tử trong danh sách, nhưng 
có thể sử dụng thẳng cho một danh sách bất kỳ mà không cần tiền xử 
lý. Tìm kiếm nhị phân là một thuật giải cao cấp hơn với thời gian 
chạy là ( ). Đối với các danh sách lớn, thuật giải này tốt hơn 
hẳn tìm kiếm tuyến tính, nhưng nó đòi hỏi danh sách phải được sắp 
xếp từ và có khả năng truy xuất ngẫu nhiên. Tìm kiếm nội suy tốt hơn 
tìm kiếm nhị phân đối với các danh sách rất lớn với phân bố gần đều. 
o Tìm kiếm trên cây: Tìm kiếm trên cây là trung tâm của các kỹ thuật 
tìm kiếm. Các thuật giải này tìm kiếm trên các cây gồm các nút, cây 
này có thể là cây tường minh hoặc được xây dựng dần trong quá trình 
tìm kiếm. Nguyên lý cơ bản là: một nút được lấy ra từ một cấu trúc dữ 
liệu, các nút con của nó được xem xét và bổ sung vào cấu trúc dữ liệu 
đó. Bằng cách thao tác trên cấu trúc dữ liệu này, cây tìm kiếm được 
duyệt theo các thứ tự khác nhau, chẳng hạn theo từng mức (tìm kiếm 
55 
theo chiều rộng) hoặc đi tới một nút lá trước rồi quay lui (tìm kiếm 
theo chiều sâu). Các ví dụ khác về tìm kiếm trên cây bao gồm: tìm 
kiếm lặp sâu dần, tìm kiếm chiều sâu giới hạn, tìm kiếm hai chiều và 
tìm kiếm chi phí đều. 
o Tìm kiếm trên đồ thị: Nhiều bài toán về lý thuyết đồ thị có thể được 
giải quyết bằng các thuật giải tìm kiếm, chẳng hạn thuật giải Dijkstra, 
thuật giải Kruskal, thuật giải láng giềng gần nhất và thuật giải Prim. 
Các thuật giải này có thể được coi là các mở rộng của các thuật giải 
tìm kiếm trên cây. 
- Tìm kiếm có thông tin: Trong tìm kiếm có thông tin, người ta sử dụng một 
đánh giá heuristic đặc thù cho bài toán cần giải quyết với vai trò hướng dẫn 
cho quá trình tìm kiếm. Một cách đánh giá heuristic tốt sẽ làm cho quá trình 
tìm kiếm có thông tin hoạt động hiệu quả hơn hẳn một phương pháp tìm 
kiếm không có thông tin bất kỳ. Có một vài thuật giải tìm kiếm có thông tin 
nổi trội dành cho danh sách. Một trong số đó là một bảng băm với một hàm 
băm là một heuristic đựa trên bài toán đang được giải. Đa số các thuật giải 
tìm kiếm có thông tin đều là tìm kiếm trên cây. Trong đó có tìm kiếm theo 
lựa chọn tốt nhất và A*. Cũng như các thuật giải không có thông tin, các 
thuật giải này có thể được mở rộng để làm việc trên cả các đồ thị. 
- Tìm kiếm đối kháng: Trong các trò chơi như cờ vua hay cờ tướng, có một 
cây trò chơi bao gồm tất cả các nước đi có thể của cả hai đấu thủ và các cấu 
hình bàn cờ là kết quả của các nước đi đó. Ta có thể tìm kiếm trên cây này để 
có được một chiến lược chơi hiệu quả. Dạng bài toán này có đặc điểm độc 
nhất vô nhị là ta phải tính đến mọi nước đi mà đối thủ của ta có thể sử dụng. 
Để làm điều này, các chương trình máy tính chơi cờ, cũng như các dạng khác 
của trí tuệ nhân tạo như lập kế hoạch tự động (machine planning), thường sử 
dụng các thuật giải tìm kiếm như thuật giải minimax, tỉa cây tìm kiếm, và tỉa 
cây alpha-beta (alpha-beta pruning). 
56 
- Tìm kiếm thỏa mãn ràng buộc: Đây là một loại tìm kiếm để giải quyết các 
bài toán thỏa mãn ràng buộc mà trong đó, thay vì tìm một đường đi, lời giải 
chỉ đơn giản là một tập các giá trị được gán cho một tập các biến. Do các 
biến có thể được xử lý theo thứ tự tùy ý, các thuật giải thông thường dành 
cho tìm kiếm trên cây rất không hiệu quả. Các phương pháp giải các bài toán 
ràng buộc bao gồm tìm kiếm tổ hợp và quay lui, cả hai đều tận dụng các đặc 
điểm tự do có liên quan đến các bài toán ràng buộc. 
- Và một số loại khác: các thuật giải tìm xâu kí tự con, thuật giải tabu, thuật 
giải di truyền, thuật giải mô phỏng tôi luyện … cũng thuộc họ giải thuật tìm 
kiếm này. 
Trong khuôn khổ của luận văn, chúng tôi chỉ đề cập đến một số các thuật giải tìm 
kiếm thông dụng như tìm kiếm theo chiều sâu, tìm kiếm theo chiều rộng, thuật giải 
A* hay thuật giải leo đồi … 
4.2 Xây dựng thuật giải tìm kiếm tổng quát 
Để xây dựng thuật giải tìm kiếm tổng quát, ta xét điểm tương đồng về bản chất của 
các thuật giải tìm kiếm. Về cơ bản, hầu hết các thuật giải tìm kiếm đều lần lượt tìm 
kiếm ứng viên lời giải trong không gian tìm kiếm và kiểm tra đây có phải lời giải 
của bài toán hay không? Thuật giải sẽ dừng khi tìm được lời giải hoặc đã duyệt hết 
không gian tìm kiếm. Mã giả thuật giải tìm kiếm tổng quát được mô tả trong bảng 
4-1. 
Bảng 4-1 Mã giải thuật giải tìm kiếm 
Thủ tục: tìm kiếm 
1. Bắt đầu với x là một lời giải bất kì của không gian tìm kiếm 
2. Nếu x là lời giải cần tìm. Dừng thuật giải à Thành công. 
3. Nếu x không là lời giải cần tìm. Thực hiện tiếp tục bước 2 
với x là phần tử kế tiếp trong danh sách chờ duyệt. Nếu 
không còn phần tử nào chưa tìm thì dừng thuật giải à Thất 
bại. 
57 
Từ mã giả trên, ta xây dựng khung giải thuật tìm kiếm kế thừa từ khung giải thuật 
tổng quát đã trình bày ở chương 2 như sau. Lớp ℎ kế thừa và cái đặt 
thuật giải tìm kiếm tổng quát () kế thừa từ lớp giải quyết bài toán tổng quát . Hàm ℎ() được gọi từ hàm () sẽ thực hiện một số lời 
gọi đến các hook của lớp thuật giải tìm kiếm tổng quát ℎ , cụ thể là 
hàm tạo danh sách chờ duyệt của các ứng viên () . Hàm () này sẽ trả về một đối tượng biểu diễn danh sách 
các ứng viên sẽ được duyệt. Thao tác trên lớp này sẽ được thực thi tại các 
lớp duyệt danh sách ứng viên của thuật giải tìm kiếm cụ thể thông qua các hàm 
hook: (), (), () … 
Bảng 4-2 Thuật giải tìm kiếm tổng quát 
class SearchSolver implements Solver { 
 public SearchSolution solveBySearch(SearchProblem problem) { 
 // khởi tạo iterator danh sách chờ duyệt ứng viên 
 SearchStrategy.Iterator iterator = 
 strategy.createExploringList(problem); 
 // lặp khi còn phần tử trong danh sách chờ duyệt 
 while (!iterator.isEmpty()) { 
 // lấy một ứng viên trong danh sách chờ duyệt 
 Object candidate = iterator.select(); 
 // nếu ứng viên này là lời giải, chọn ứng viên làm lời giải 
 // và dừng việc lặp 
 if (problem.isSolution(candidate) { 
 return SearchSolution.makeSolution(candidate); 
 } 
 // mở rộng danh sách ứng viên chờ duyệt 
 iterator.explore(problem, candidate); 
 } 
 return SearchSolution.makeSolution(null); 
 } 
} 
interface SearchProblem extends Problem { 
58 
 boolean isSolution(Object choices); 
 Object getInitState(); 
 Iterator explore(Object candidate); 
}; 
interface SearchSolution extends Solution {} 
abstract class SearchStrategy implements Strategy { 
 static abstract class Iterator { 
 public abstract boolean isNotEmpty (); 
 public abstract Object select (); 
 public abstract void explore (SearchProblem p, Object c); 
 public abstract void add(Object c); 
 } 
 // tạo danh sách chờ duyệt các ứng viên 
 protected abtract Iterator createExploringList(SearchProblem p); 
} 
Với cách triển khai như trên, ta có thể mô hình hóa lại khung giải thuật tìm kiếm 
tương tự cách mô hình hóa các thuật giải ở chương 3 như Hình 5-1. 
Hình 4-1 Thuật giải tìm kiếm tổng quát 
59 
4.3 Các thuật giải tìm kiếm cụ thể 
Sau khi xây dựng xong giải thuật tìm kiếm tổng quát, ta lần lượt bổ sung vào khung 
giải thuật tìm kiếm các giải thuật tìm kiếm cụ thể. Các giải thuật tìm kiếm này sẽ 
lần lượt kế thừa thuật giải tìm kiếm tổng quát và kế thừa các hàm hook liên quan 
đến thứ tự chờ duyệt của không gian tìm kiếm. 
4.3.1 Thuật giải tìm kiếm ưu tiên chiều sâu 
Thuật giải tìm kiếm ưu tiên chiều sâu (depth-first-search) là một dạng thuật giải tìm 
kiếm thông tin không đầy đủ. Quá trình tìm kiếm bắt đầu từ một phần tử trong 
không gian tìm kiếm rồi duyệt tiếp phần tử kế tiếp chưa được duyệt của phần tử này. 
Bước lặp trên được thực hiện liên tục đến khi phần tử vừa duyệt là không còn phần 
tử nào kế tiếp, thuật giải sẽ quay lui lại phần tử mới vừa duyệt ở bước kế trước. Khi 
thực thi thuật giải dưới dạng không đệ quy, thứ tự các phần tử chờ duyệt sẽ được 
lần lượt bổ sung vào một ngăn xếp. 
Với bản chất thuật giải như vậy, ta nhận thấy thuật giải tìm kiếm ưu tiên chiều sâu 
sẽ kế thừa thuật giải tìm kiếm tổng quát với thứ tự của danh sách chờ duyệt là “vào 
sau ra trước”. Ta xây dựng lớp thuật giải tìm kiếm ưu tiên chiều sâu ℎ ℎ kế thừa từ ℎ trong đó hàm hook () sẽ tạo ra một đối tượng ℎ kế thừa từ ℎ . . ℎ sẽ hoạt động theo cơ chế “vào 
sau ra trước”. Khi cài đặt bằng ngôn ngữ lập trình Java, ta có thể sử dụng một hoặc một với thao tác thêm phần tử vào đầu 
danh sách và lấy phần tử ở cuối danh sách. 
Mã giã thuật giải tìm kiếm ưu tiên chiều sâu cài đặt kế thừa từ thuật giải tìm kiếm 
tổng quát được mô tả trong Bảng 4-3. 
60 
Bảng 4-3 Thuật giải tìm kiếm ưu tiên chiều sâu 
class DepthFirstSearch extends SearchStrategy { 
 class DepthFirstIterator extends SearchStrategy.Iterator { 
 // cài đặt lớp duyệt ứng viên theo cơ chế vào sau ra trước 
 // với phần tử ban đầu bất kì theo yêu cầu của bài toán 
 } 
 protected Iterator createExploringList (SearchProblem p) { 
 return new DepthFirstIterator (p); 
 } 
} 
4.3.2 Thuật giải tìm kiếm ưu tiên chiều rộng 
Thuật giải tìm kiếm ưu tiên chiều rộng (breadth-first-search) là một dạng thuật giải 
tìm kiếm thông tin không đầy đủ. Quá trình tìm kiếm bắt đầu từ một phần tử trong 
không gian tìm kiếm rồi duyệt qua tất cả phần tử kế tiếp chưa được duyệt của phần 
tử này. Sau đó, ứng với mỗi phần tử kế đó, thuật giải lại duyệt hết các phần tử kế 
của nó. Và liên tục lặp như vậy đến khi tìm ra lời giải hoặc thuật giải đã duyệt qua 
tất cả phần tử của không gian tìm kiếm. Khi thực thi thuật giải dưới dạng không đệ 
quy, thứ tự các phần tử chờ duyệt sẽ được lần lượt bổ sung vào một hàng đợi. 
Với bản chất thuật giải như vậy, ta nhận thấy thuật giải tìm kiếm ưu tiên chiều rộng 
sẽ kế thừa thuật giải tìm kiếm tổng quát với thứ tự của danh sách chờ duyệt là “vào 
trước ra trước”. Tương tự như ℎ ℎ, ta xây dựng lớp thuật giải tìm 
kiếm ưu tiên chiều rộng ℎ ℎ kế thừa từ ℎ trong 
đó hàm hook () sẽ tạo ra một đối tượng ℎ hoạt động theo cơ chế “vào trước ra trước”. Khi cài đặt 
bằng ngôn ngữ lập trình Java, ta có thể sử dụng một hoặc một với thao tác thêm phần tử vào cuối danh sách và lấy 
phần tử ở cuối danh sách. 
61 
Mã giã thuật giải tìm kiếm ưu tiên chiều rộng cài đặt dựa trên khung thuật giải tìm 
kiếm được mô tả trong Bảng 4-4. 
Bảng 4-4 Thuật giải tìm kiếm ưu tiên chiều rộng 
class BreadthFirstSearch extends SearchStrategy { 
 class BreadthFirstIterator extends SearchStrategy.Iterator { 
 // cài đặt lớp duyệt ứng viên theo cơ chế vào trước ra trước 
 // với phần tử đầu tiên bất kì theo yêu cầu của bài toán 
 } 
 protected Iterator createExploringList (SearchProblem p) { 
 return new BreadthFirstIterator (p); 
 } 
} 
4.3.3 Thuật giải tìm kiếm ưu tiên lựa chọn tốt nhất 
4.3.3.1 Thuật giải tìm kiếm ưu tiên lựa chọn tốt nhất tổng quát 
Thuật giải tìm kiếm ưu tiên lựa chọn tốt nhất (best-first-search) là một dạng của tìm 
kiếm có thông tin. Nó duyệt qua không gian tìm kiếm theo thứ tự ưu tiên của các 
phần tử theo một quy tắc đặt trước. Judea Pearl mô tả thuật giải tìm kiếm ưu tiên 
lựa chọn tốt nhất được thực hiện bởi việc ước lượng giá trị thỏa mãn lời giải của 
phần tử n bởi một hàm lượng giá heuristic. Hàm lượng giá này sẽ phụ thuộc vào giá 
trị của phần tử n, yêu cầu của lời giải, và những thông tin thu thập trong quá trình 
duyệt trước đó và quan trọng nhất là phụ thuộc vào mọi tri thức bổ sung về miền 
xác định của bài toán. Các thuật giải tìm kiếm theo lựa chọn tốt nhất thường được 
sử dụng để tìm đường trong quá trình tìm kiếm tổ hợp, ví dụ như thuật giải và thuật giải tìm kiếm ∗… 
Rõ ràng về mặt bản chất, thuật giải tìm kiếm ưu tiên lựa chọn tốt nhất hoàn toàn 
tương thích với thuật giải tìm kiếm tổng quát đã trình bày ở Mục 5-2, chỉ khác ở 
62 
danh sách thứ tự chờ duyệt của các ứng viên. Để tăng hiệu quả cho việc thực thi, 
danh sách chờ duyệt này sẽ được cài đặt bằng một hàng đợi ưu tiên. 
Từ đó, ta có thể xây dựng lớp thuật giải tìm kiếm ưu tiên lựa chọn tốt 
nhất ℎ kế thừa từ ℎ trong đó hàm hook () sẽ tạo ra một đối tượng hoạt động 
theo cơ chế chọn phần tử có giá trị hàm lượng giá tốt nhất. Khi cài đặt bằng ngôn 
ngữ lập trình Java, ta thể sử dụng kết hợp với một lớp Comparator 
để so sánh hàm lượng giá . Comparator là lớp tổng quát biểu diễn hàm so 
sánh và biểu diễn hàm lượng giá bất kì. Hai lớp này có sẵn trong STL 
của C++ ( và ), khi sử dụng ta phải cài đặt lại 
theo cơ chế tương tự. 
Bảng 4-5 Thuật giải tìm kiếm ưu tiên lựa chọn tốt nhất 
class BestFirstSearch extends SearchStrategy { 
 class BestFirstIterator extends SearchStrategy.Iterator { 
 public BestFirstIterator(SearchProblem p, Function f) { 
 // tạo mới hàng đợi ưu tiên với comparator theo f 
 } 
 public Object select () { 
 // hàm này trả về vị trí đầu tiên của hàng đợi ưu tiên 
 } 
 public void explore () { 
 // thêm phần tử mới vào hàng đợi và cập nhật lại thứ tự 
 } 
 } 
 protected Iterator createExploringList (SearchProblem p) { 
 return new BestFirstIterator (p, getEvalFunc() ); 
 } 
} 
63 
4.3.3.2 Thuật giải A* 
Thuật giải A* là một thuật giải tìm kiếm có thông tin được sử dụng để tìm một 
đường đi từ một phần tử khởi đầu tới một phần tử đích cho trước (hoặc tới một phần 
tử thỏa mãn một điều kiện đích). Thuật giải này sử dụng một hàm lượng giá 
heuristic để xếp loại từng phần tử theo ước lượng về tuyến đường tốt nhất đi qua 
phần tử đó và duyệt các phần tử theo thứ tự của đánh giá heuristic này. Do đó, thuật 
toán ∗ là một trường hợp của tìm kiếm ưu tiên lựa chọn tốt nhất (best-first search). 
Do xác định thuật giải ∗ chính là một trường hợp của thuật giải ưu tiên lựa chọn 
tốt nhất nên ta dễ dàng xây dựng lớp AStar biểu diễn thuật giải ∗ kế thừa trực tiếp 
từ thuật giải best-first search. 
Bảng 4-6 Thuật giải A* 
class AStar extends BestFirstSearchStrategy { 
 protected Function getEvalFunc() { 
 // trả về hàm lượng giá heuristic 
 } 
} 
4.3.4 Thuật giải tìm kiếm cục bộ 
4.3.4.1 Thuật giải tìm kiếm cục bộ tổng quát 
Thuật giải tìm kiếm cục bộ (hoặc thuật giải tìm kiếm địa phương) là giải pháp 
metaheuristic cho việc giải các bài toán tính toán tối ưu khó trong máy tính. Thuật 
giải này có thể được áp dụng cho các bài toán tìm kiếm lời giải gần đúng tối ưu 
trong một loạt các lời giải ứng viên. Phương pháp tìm kiếm sẽ duyệt qua các lời giải 
trong không gian tìm kiếm cho đến khi lời tìm ra lời giải được cho là tối ưu hoặc 
vượt quá thời gian tìm kiếm cho phép. Một số bài toán kinh điển có thể áp dụng 
64 
thuật giải tìm kiếm cục bộ như: bài toán người du lịch, bài toán xếp lịch trực y tá, 
bài toán tìm tập phủ đỉnh của đồ thị … 
Thuật giải tìm kiếm cục bộ sẽ bắt đầu từ một ứng viên lời giải, kiểm tra và liên tục 
chọn sang ứng viên lời giải kế tiếp (hay ứng viên láng giềng) đến khi dừng thuật 
giải. Tuy nhiên mỗi ứng viên lời giải đều có thể có hơn một lời giải láng giềng, cho 
nên mỗi cách lựa chọn lời giải láng giềng trong danh sách láng giềng để thành bước 
duyệt kế tiếp có thể trở thành một thuật giải khác. 
Bảng 4-7 Thuật giải tìm kiếm cục bộ 
abtract class LocalSearch extends SearchStrategy { 
 abtract class LocalSearchIterator extends 
 SearchStrategy.Iterator { 
 public Object select () { 
 // trả về phần tử đang chờ duyệt hoặc null 
 } 
 public void explore () { 
 // chọn chỉ một phần tử láng giềng làm phần tử chờ duyệt 
 // kế tiếp 
 } 
 } 
 protected Iterator createExploringList (SearchProblem p) { 
 return new LocalSearchIterator (p); 
 } 
} 
4.3.4.2 Thuật giải leo đồi 
Thuật giải leo đồi là kỹ thuật giải bài toán theo phương pháp toán tối ưu, thuộc họ 
thuật giải tìm kiếm cục bộ. Ở mỗi bước chọn phần tử kế tiếp trong thuật giải tìm 
kiếm cục bộ, thuật giải leo đồi chọn phần tử có giá trị tương thích cao nhất theo một 
hàm lượng giá có sẵn. Mã giả thuật giải leo đồi được thể hiện trong Bảng 4-8 
65 
Bảng 4-8 Mã giả thuật giải leo đồi 
Hill Climbing Algorithm 
 currentNode = startNode; 
 loop do 
 L = NEIGHBORS(currentNode); 
 nextEval = -INF; = NULL; 
 for all x in L 
 if (EVAL(x) > nextEval) 
 nextNode = x; = EVAL(x); 
 if nextEval <= EVAL(currentNode) 
 return currentNode; 
 currentNode = nextNode; 
Tuy nhiên, khi cài đặt thuật giải leo đồi trong khung thuật giải tìm kiếm. Ta nhận 
xét rằng thuật giải leo đồi là một trường hợp của thuật giải tìm kiếm cục bộ. Do vậy 
ta có thể cài đặt thuật giải leo đồi kế thừa từ thuật giải tìm kiếm cục bộ như sau: 
Bảng 4-9 Thuật giải leo đồi kế thừa từ thuật giải tìm kiếm cục bộ 
class HillClimbing extends LocalSearch { 
 abtract class HillClimbingIterator extends 
 SearchStrategy.Iterator { 
 public Object select () { 
 // trả về phần tử đang chờ duyệt hoặc null 
 } 
 public void explore () { 
 // chọn chỉ một phần tử láng giềng có giá trị tương thích 
 // cao nhất làm phần tử kế tiếp 
 } 
 } 
 protected Iterator createExploringList (SearchProblem p) { 
 return new HillClimbingIterator (p, getEvalFunc() ); 
 } 
} 
66 
4.4 Tổng kết 
Như vậy qua quá trình xây dựng thuật giải tìm kiếm tổng quát và các thuật giải tìm 
kiếm cụ thể giải thuật kế thừa từ lớp thuật giải tìm kiếm ℎ , ta đã 
hình thành một khung thuật giải gọi là khung thuật giải dành cho các thuật giải tìm 
kiếm. Mỗi thuật giải tìm kiếm cụ thể sẽ cài đặt hàm nhượng quyền lại một số hàm 
của lớp thuật giải tổng quát, và quan trọng nhất là hàm select() để chọn một phần tử 
và hàm explore() để cập nhật danh sách ứng viên chờ duyệt. 
Thuật giải Cài đặt hàm nhượng quyền Ghi chú 
Depth-First-
Search 
select(): Chọn ứng viên mới đưa vào, xóa khỏi danh 
sách 
explore(c): Đưa vào danh sách các phần tử kề của c 
Stack 
Breadth-
First-Search 
select(): Chọn ứng viên sớm nhất trong danh sách, 
xóa khỏi danh sách 
explore(c): Đưa vào danh sách các phần tử kề của c 
Queue 
Best-First-
Search 
select(): Chọn ứng viên có giá trị lượng giá cao nhất 
trong danh sách, xóa khỏi danh sách 
explore(c): Đưa vào danh sách các phần tử