Thuật toán Depth First Search
Cấu trúc Graph (đồ thị) gồm tập các đỉnh kết nối với nhau qua các cạnh. Depth First Search (DFS) là một trong những thuật toán có thể dùng để duyệt qua đồ thị.
Mục lục
1. Ý tưởng
Ý tưởng như sau:
- Từ một đỉnh, ta đi qua sâu vào từng nhánh. Khi đã duyệt hết nhánh của đỉnh, lùi lại để duyệt đỉnh tiếp theo.
- Thuật toán dừng khi đi qua hết tất cả các đỉnh có thể đi qua.
2. Hiện thực
Hai cách hiện thực dưới đây được dùng cho cấu trúc Graph ở bài viết Tổng quan về Đồ thị.
2.1. Đệ quy
Hiện thực theo phương pháp đệ quy khá đơn giản và dễ hiểu. Ta cần dùng một mảng marked
để kiểm tra xem một đỉnh đã được duyệt qua chưa.
Đầu vào cần một Graph
và đỉnh gốc v
. Các bước như sau:
- Đánh dấu điểm gốc
v
đã duyệt qua. - Lấy danh sách các đỉnh kề của
v
. Với mỗi đỉnhi
:- Nếu
i
chưa được duyệt qua thì chọni
làm đỉnh gốc mới và lặp lại thủ tục trên.
- Nếu
Code tham khảo:
- java
1 |
|
2.2. Khử đệ quy
Với phương pháp không dùng đệ quy, cách hiện thực hơi phức tạp hơn chút. Lúc này phải dùng một Stack
để xét các đỉnh chưa duyệt.
Đầu vào là một Graph
và đỉnh gốc v
. Các bước như sau:
- Thêm đỉnh gốc vào
stack
. - Lặp lại với điều kiện
stack
không rỗng:- Lấy đỉnh ở đầu
stack
làm đỉnh đang xét. - Nếu đỉnh đang xét đã được duyệt thì bỏ qua. (*)
- Đánh dấu đỉnh đang xét là đỉnh đã duyệt.
- Lấy danh sách các đỉnh kề của đỉnh đang xét. Với mỗi đỉnh
i
:- Nếu
i
chưa được duyệt qua thì đẩyi
vàostack
.
- Nếu
- Lấy đỉnh ở đầu
Code tham khảo:
- java
1 |
|
- (*) Nếu không làm bước này, sẽ xảy ra trường hợp một đỉnh chưa được duyệt được thêm vào
stack
nhiều lần và kết quả là sẽ được duyệt qua nhiều lần. - Kết quả duyệt của phương pháp khử đệ quy có thể khác với phương pháp đệ quy do cấu trúc Stack hoạt động theo cơ chế LIFO. Nghĩa là thêm các đỉnh kề vào thì sẽ lấy ra theo thứ tự ngược lại. Tuy nhiên, nó vẫn tuân theo nguyên lý của DFS là duyệt sâu nhất có thể nên vẫn hợp lệ.
3. Áp dụng
Bài toán: Cho đồ thị g
và đỉnh gốc s
. Trả lời câu hỏi, có đường đi nào từ đỉnh gốc s
tới một đỉnh w
nào đó không. Nếu có, hãy tìm đường đi đó.
Chúng ta sẽ dùng thuật toán DFS để duyệt qua các đỉnh. Trong quá trình duyệt đó, lưu lại đỉnh gần nhất tới đỉnh a
nào đó sử dụng edgeTo[]
.
Nếu các đỉnh được duyệt qua trong marked[]
, chứng tỏ có đường đi đến đỉnh đó và có thể truy hồi lại đường đi dùng edgeTo[]
.
Code tham khảo:
- java
1 |
|
Cùng thử nghiệm với đồ thị sau đây:
Viết hàm main
để test:
- java
1 |
|
Kết quả là:
[0]
[0, 1]
[0, 1, 4, 2]
[0, 3]
[0, 1, 4]
[0, 1, 4, 2, 5]
Và đường đi mà thuật toán cho kết quả là:
Có gì đó sai sai đúng không 😆
Thật ra DFS là thuật toán tìm kiếm mù và do cách duyệt vét cạn này, nó sẽ bị ảnh hưởng bởi thứ tự thêm cạnh vào đồ thị. Thử đặt dòng g.addEdge(0, 2);
lên trên dòng g.addEdge(0, 1);
rồi chạy lại. Bạn sẽ thấy sự khác biệt.
4. Đánh giá
Thuật toán sẽ duyệt qua tất cả các đỉnh nếu đồ thị liên thông. Tuy vậy, nó là thuật toán tìm kiếm mù, mang tính chất vét cạn và sẽ kém hiệu quả nếu tập đỉnh quá lớn.
Bình luận
Cảm ơn bạn
Your comment has been submitted and will be published once it has been approved. 😊
OK