diff --git a/python/31_bfs_dfs/bfs_dfs.py b/python/31_bfs_dfs/bfs_dfs.py new file mode 100644 index 0000000..59cebd8 --- /dev/null +++ b/python/31_bfs_dfs/bfs_dfs.py @@ -0,0 +1,88 @@ +""" + Breadth-first search and depth-first search. + + Author: Wenru Dong +""" + +from typing import List, Optional, Generator, IO +from collections import deque + +class Graph: + """Undirected graph.""" + def __init__(self, num_vertices: int): + self._num_vertices = num_vertices + self._adjacency = [[] for _ in range(num_vertices)] + + def add_edge(self, s: int, t: int) -> None: + self._adjacency[s].append(t) + self._adjacency[t].append(s) + + def _generate_path(self, s: int, t: int, prev: List[Optional[int]]) -> Generator[str, None, None]: + if prev[t] or s != t: + yield from self._generate_path(s, prev[t], prev) + yield str(t) + + def bfs(self, s: int, t: int) -> IO[str]: + """Print out the path from Vertex s to Vertex t + using bfs. + """ + if s == t: return + + visited = [False] * self._num_vertices + visited[s] = True + q = deque() + q.append(s) + prev = [None] * self._num_vertices + + while q: + v = q.popleft() + for neighbour in self._adjacency[v]: + if not visited[neighbour]: + prev[neighbour] = v + if neighbour == t: + print("->".join(self._generate_path(s, t, prev))) + return + visited[neighbour] = True + q.append(neighbour) + + def dfs(self, s: int, t: int) -> IO[str]: + """Print out a path from Vertex s to Vertex t + using dfs. + """ + found = False + visited = [False] * self._num_vertices + prev = [None] * self._num_vertices + + def _dfs(from_vertex: int) -> None: + nonlocal found + if found: return + visited[from_vertex] = True + if from_vertex == t: + found = True + return + for neighbour in self._adjacency[from_vertex]: + if not visited[neighbour]: + prev[neighbour] = from_vertex + _dfs(neighbour) + + _dfs(s) + print("->".join(self._generate_path(s, t, prev))) + + +if __name__ == "__main__": + + graph = Graph(8) + + graph.add_edge(0, 1) + graph.add_edge(0, 3) + graph.add_edge(1, 2) + graph.add_edge(1, 4) + graph.add_edge(2, 5) + graph.add_edge(3, 4) + graph.add_edge(4, 5) + graph.add_edge(4, 6) + graph.add_edge(5, 7) + graph.add_edge(6, 7) + + graph.bfs(0, 7) + graph.dfs(0, 7)