5 KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN
2.8 Ví dụ về duyệt theo chiều rộng trước
Xét bài tốn tìm đỉnh t từ đỉnh gốc v trong đồ thị G thỏa mãn điều kiện tìm kiếm C (chẳng hạn, khoảng cách từv đếnt là10). Mã giả cho giải thuật duyệt đồ thịGtừ đỉnh gốc v theo chiều rộng trước được minh hoạ như sau [83]:
Thuật toán 2.1: BF S(G, v): Mã giả phương pháp duyệt theo chiều rộng trước
1 Function BF S(G, v)
Input:G= (V, E);v ∈V; điều kiện tìm kiếm C Output: t ∈V thoả mãn điều kiện tìm kiếm C
2 if v thoả mãn điều kiện tìm kiếm then return v ;
3 Tạo mảng lưu vết đỉnh đã duyệt Seen[|V|] và khởi tạo giá trị F alse ;
4 Seen[v] =T rue ; /* đánh dấu v đã được duyệt */
5 Tạo hàng đợiQ và đưa v vào Q←v ;
6 while Q6=∅ do
7 t ←Q.dequeue() ;
8 forall u∈G.adjacentN odes(t) do /* xét các đỉnh liền kề của t */
9 if !Seen[u] then
10 if u thoả mãn điều kiện tìm kiếm C then returnu ;
11 Seen[u] =T rue ; /* đánh dấu u đã duyệt */
12 Q←u ; /* đưa u vào hàng đợi */
13 end
14 end
15 end
16 returnnull ;
Trong giải thuật 2.1, chúng ta sử dụng một hàng đợi Q để lưu những đỉnh liền kề với đỉnh đang thăm hiện thời mà chưa được duyệt. Mỗi khi thăm một đỉnh, chúng ta sẽ đánh dấu lại đỉnh đã duyệt bằng cách sử dụng một vector kiểu bool có độ lớn bằng số đỉnh của
G, nhằm tránh việc duyệt lại hay thậm chí tạo vịng lặp bất tận. Với phương pháp tổ chức dữ liệu đồ thị dưới dạng danh sách đỉnh liền kề, mỗi khi duyệt một đỉnh, chúng ta sẽ đưa tồn bộ các đỉnh liền kề với nó (xác định dựa vào hàm G.adjacentN odes(v)) còn chưa được thăm vào trong hàng đợi Q. Như vậy, với việc tổ chức hàng đợi các đỉnh sẽ duyệt, BFS sẽ cho phép chúng ta thăm các đỉnh tuần tự theo độ sâu kể từ đỉnh gốc cần tìm.
Định lý 2.1. Độ phức tạp tính tốn của phương pháp BFS duyệt theo chiều rộng trước là
O(|V|+|E|).
Thật vậy, với giải thuật 2.1, số đỉnh tối đa chúng ta có thể đưa vào hàng đợi Q là V. Ngồi ra, với vịng lặp F orAll, số cạnh tối đa chúng ta thăm trong giải thuật này là V. Do đó, độ phức tạp tính tốn theo thời gian của giải thuật này là O(|V|+|E|).
Phương pháp duyệt BFS cho phép giải quyết được rất nhiều bài toán đồ thị, chẳng hạn như: kiểm tra khả năng hai phía (bipartiteness) của đồ thị; tìm đường đi ngắn nhất về số cạnh giữa hai đỉnh; tính luồng cực đại trong mạng theo phương pháp Ford-Fulkerson; xây dựng hàm lỗi theo giải thuật Aho-Corasick; ... [38].
2.3.1.2 Duyệt theo chiều sâu trước - DFS
Định nghĩa 2.19. Duyệt theo chiều sâu trước (Depth-First Search - DFS) là giải thuật để duyệt cấu trúc dữ liệu đồ thị, cho phép từ một đỉnh trong đồ thị, gọi là đỉnh gốc, khám phá càng xa càng tốt dọc theo từng đỉnh liền kề trước khi quay trở lại. Hay khác với BFS khám phá các đỉnh anh em cùng mức trước, DFS cho phép khám phá các đỉnh con trước khi quay lại khám phá các đỉnh anh em [33].
Với cách tiếp cận duyệt đồ thị như vậy, giải thuật duyệt DFS thường sử dụng ngăn xếp (stack) để lưu các đỉnh chưa duyệt. Xét bài tốn như ở mục trên: tìm đỉnh t từ đỉnh gốc v trong đồ thị Gthỏa mãn điều kiện tìm kiếmC. Khi đó, mã giả của DFS được minh hoạ như
sau:
Thuật toán 2.2: DF S(G, v): Mã giả phương pháp duyệt theo chiều sâu trước
1 Function DFS(G,v)
Input:G= (V, E);v ∈V; điều kiện tìm kiếm C Output: u∈V thoả mãn điều kiện tìm kiếm C
2 if v thoả mãn điều kiện tìm kiếm then return v;
3 Tạo mảng lưu vết đỉnh đã duyệt Seen[|V|] và khởi tạo giá trị F alse ;
4 Seen[v] =T rue ; /* đánh dấu v đã được duyệt */
5 Tạo ngăn xếp S và đưa v vàoS ←v ;
6 while S6=∅ do
7 t ←S.pop();
8 forall u∈G.adjacentN odes(v)do /* xét các đỉnh liền kề của t */
9 if !Seen[u] then
10 if u thoả mãn điều kiện tìm kiếm C then return u;
11 S ←u ; /* đưa u vào ngăn xếp */
12 Seen[u] =T rue ; /* đánh dấu u đã được duyệt */
13 end
14 end
15 end
16 returnnull ;
Với DFS, ta sẽ bắt đầu thăm đỉnh "gốc" v đã chọn. Nếu đỉnh này chưa thoả mãn điều kiện tìm kiếm, chúng ta sẽ chọn lần lượt các đỉnh liền kề uvới v để duyệt tiếp. Với mỗi đỉnh u chưa được thăm (dựa vào vector kiểu bool có độ lớn bằng số đỉnh của V), chúng ta sẽ duyệt đệ quy để thăm tiếp đỉnh con của u. Sau khi thăm xong tất cả các đỉnh con củaumà khơng tìm thấy kết quả mong muốn, DFS mới quay lui lại để xét tiếp các đỉnh cùng mức (hay các đỉnh anh em) với u. Chính vì vậy, DFS sẽ có phép duyệt các đỉnh trong đồ thị theo chiều sâu trước. Hình dưới đây minh hoạ quá trình duyệt các đỉnh theo DFS từ đỉnh gốc 0
[72]: