Luận bàn về Depth First Search (DFS)
Bên canh BFS, ta còn có 1 kiểu traverse graph hay dùng nữa, gọi là Depth First Search. Khác với BFS duyệt từng level của graph, thì ở DFS ta sẽ đi sâu thẳng 1 đường từ node xuất phát cho tới leaf node
(node mà không còn node liền kề nào có thể đi được nữa).
RootNode
/ \
Node1 Node2
/ \ / \
LeafNode1 LeafNode2 LeafNode3 LeafNode4
Với DFS, ta xuất phát từ RootNode => đi xuống Node1 => đi xuống LeafNode1 (ở node này ko còn node liền kề mà chưa ta chưa đi nữa) => quay lại Node1 => LeafNode2 => quay lại Node1 (lúc này thì Node1 cũng hết node để đi) => quay lại RootNode => Node2 => LeafNode3 => quay lại Node2 => LeafNode4 => quay lại Node2 (cũng hết node để đi rồi) => quay lại RootNode và kết thúc.
Có thể thấy ta sẽ đi thẳng 1 mạch từ RootNode xuống LeafNode1 trước, rồi khi mà ko còn node nào có thể di chuyển tới được nữa, ta quay lại node ở trước node hiện tại của ta, và tiến tới các node khác chưa đi.
Cái cơ chế trên thì chắc hẳn đọc qua anh em cũng thấy quen quen. Yup =))) Đây chính là đệ quy. Cái khúc ta tới LeafNode rồi quay lại Node rồi đi tiếp LeafNode tiếp theo chính là giải thích cho việc tại hàm Node, ta gọi đệ quy tới hàm LeafNode đầu, xử lý xong thì ta trở lại hàm Node và gọi tới hàm LeafNode tiếp theo.
f(RootNode)
=> f(Node1)
=> f(LeafNode1)
=> f(LeafNode2)
=> f(Node2)
=> f(LeafNode3)
=> f(LeafNode4)
Từ cách hiểu trên, ta xây dựng được 1 pseudocode sau:
Recursive function starts at a Node:
Check base case of the Node
Repeat all childNodes:
Call the recursive function to a childNode
End repeat
Return the required value
Snippet:
# Python
def dfs(node):
# Base case
if node_is_base_case_or_leaf_node():
return
do_something()
# Call to recursive function
dfs(node.child1)
dfs(node.child2)
Follow up
Khi ta áp dụng đệ qui như trên, đối với graph sẽ có nhiều trường hợp 1 node sẽ được đi lặp lại nhiều lần, vậy nên ta cũng cần dùng hash table để đảm bảo việc mỗi node sẽ chỉ phải duyệt 1 lần.
Code snippet sẽ được updated lại như sau:
# Init a new set as a global variable
visit = set()
def dfs(node):
# Base case
if node_is_base_case_or_leaf_node():
return
if node in visit:
return
do_something()
# Call to recursive function
dfs(node.child1)
dfs(node.child2)
visit.put(node)