|
| 1 | +""" |
| 2 | + Breadth-first search and depth-first search. |
| 3 | +
|
| 4 | + Author: Wenru Dong |
| 5 | +""" |
| 6 | + |
| 7 | +from typing import List, Optional, Generator, IO |
| 8 | +from collections import deque |
| 9 | + |
| 10 | +class Graph: |
| 11 | + """Undirected graph.""" |
| 12 | + def __init__(self, num_vertices: int): |
| 13 | + self._num_vertices = num_vertices |
| 14 | + self._adjacency = [[] for _ in range(num_vertices)] |
| 15 | + |
| 16 | + def add_edge(self, s: int, t: int) -> None: |
| 17 | + self._adjacency[s].append(t) |
| 18 | + self._adjacency[t].append(s) |
| 19 | + |
| 20 | + def _generate_path(self, s: int, t: int, prev: List[Optional[int]]) -> Generator[str, None, None]: |
| 21 | + if prev[t] or s != t: |
| 22 | + yield from self._generate_path(s, prev[t], prev) |
| 23 | + yield str(t) |
| 24 | + |
| 25 | + def bfs(self, s: int, t: int) -> IO[str]: |
| 26 | + """Print out the path from Vertex s to Vertex t |
| 27 | + using bfs. |
| 28 | + """ |
| 29 | + if s == t: return |
| 30 | + |
| 31 | + visited = [False] * self._num_vertices |
| 32 | + visited[s] = True |
| 33 | + q = deque() |
| 34 | + q.append(s) |
| 35 | + prev = [None] * self._num_vertices |
| 36 | + |
| 37 | + while q: |
| 38 | + v = q.popleft() |
| 39 | + for neighbour in self._adjacency[v]: |
| 40 | + if not visited[neighbour]: |
| 41 | + prev[neighbour] = v |
| 42 | + if neighbour == t: |
| 43 | + print("->".join(self._generate_path(s, t, prev))) |
| 44 | + return |
| 45 | + visited[neighbour] = True |
| 46 | + q.append(neighbour) |
| 47 | + |
| 48 | + def dfs(self, s: int, t: int) -> IO[str]: |
| 49 | + """Print out a path from Vertex s to Vertex t |
| 50 | + using dfs. |
| 51 | + """ |
| 52 | + found = False |
| 53 | + visited = [False] * self._num_vertices |
| 54 | + prev = [None] * self._num_vertices |
| 55 | + |
| 56 | + def _dfs(from_vertex: int) -> None: |
| 57 | + nonlocal found |
| 58 | + if found: return |
| 59 | + visited[from_vertex] = True |
| 60 | + if from_vertex == t: |
| 61 | + found = True |
| 62 | + return |
| 63 | + for neighbour in self._adjacency[from_vertex]: |
| 64 | + if not visited[neighbour]: |
| 65 | + prev[neighbour] = from_vertex |
| 66 | + _dfs(neighbour) |
| 67 | + |
| 68 | + _dfs(s) |
| 69 | + print("->".join(self._generate_path(s, t, prev))) |
| 70 | + |
| 71 | + |
| 72 | +if __name__ == "__main__": |
| 73 | + |
| 74 | + graph = Graph(8) |
| 75 | + |
| 76 | + graph.add_edge(0, 1) |
| 77 | + graph.add_edge(0, 3) |
| 78 | + graph.add_edge(1, 2) |
| 79 | + graph.add_edge(1, 4) |
| 80 | + graph.add_edge(2, 5) |
| 81 | + graph.add_edge(3, 4) |
| 82 | + graph.add_edge(4, 5) |
| 83 | + graph.add_edge(4, 6) |
| 84 | + graph.add_edge(5, 7) |
| 85 | + graph.add_edge(6, 7) |
| 86 | + |
| 87 | + graph.bfs(0, 7) |
| 88 | + graph.dfs(0, 7) |
0 commit comments