Depth-first search

A stack (or recursion) on an adjacency list. Recursion vs BFS.

DFS explores as far as possible along each branch, then backtracks. Implement it with a stack or with recursion. BFS (CS course) uses a queue and finds hop-shortest paths. DFS does not.

Goal

DFS a Kenya graph from Nairobi and print the visit order.

Recursive DFS

graph = {
    "Nairobi": ["Nakuru", "Mombasa"],
    "Mombasa": ["Nairobi", "Kisumu"],
    "Kisumu": ["Mombasa", "Nakuru"],
    "Nakuru": ["Nairobi", "Kisumu", "Eldoret"],
    "Eldoret": ["Nakuru"],
}

def dfs(graph, start):
    seen = set()
    order = []

    def visit(node):
        if node in seen:
            return
        seen.add(node)
        order.append(node)
        for nbr in graph[node]:
            visit(nbr)

    visit(start)
    return order

print(dfs(graph, "Nairobi"))

Stack DFS (same idea)

graph = {
    "Nairobi": ["Nakuru", "Mombasa"],
    "Nakuru": ["Nairobi", "Eldoret"],
    "Mombasa": ["Nairobi"],
    "Eldoret": ["Nakuru"],
}

def dfs_stack(graph, start):
    seen = {start}
    stack = [start]
    order = []
    while stack:
        node = stack.pop()
        order.append(node)
        for nbr in reversed(graph[node]):
            if nbr not in seen:
                seen.add(nbr)
                stack.append(nbr)
    return order

print(dfs_stack(graph, "Nairobi"))

Neighbour order changes the walk. Mark seen when you first discover a node so cycles do not loop forever.

Tip

DFS is the engine under topological sort and “are these two cities in the same connected piece?”. Shortest hops still want BFS. Weighted kilometres want Dijkstra.