def topological_sort_kahn(graph: Graph) -> list: """ Ex 22.4-5. If return list is shorter than graph vertex length, it means the topological sort cannot be performed. O(V + E) time. """ in_degrees = {} ret = [] for v_key in graph.vertex_keys(): in_degrees[v_key] = 0 for u_key in graph.vertex_keys(): for v_key, _ in graph.get_vertex(u_key).successors(): in_degrees[v_key] += 1 zero_in_degree_set = deque() for v_key in graph.vertex_keys(): if in_degrees[v_key] == 0: zero_in_degree_set.append(v_key) while zero_in_degree_set: u_key = zero_in_degree_set.popleft() ret.append(u_key) for v_key, _ in list(graph.get_vertex(u_key).successors()): graph.remove_edge(u_key, v_key) in_degrees[v_key] -= 1 if in_degrees[v_key] == 0: zero_in_degree_set.append(v_key) return ret
def get_transpose(graph: Graph): """Ex 22.1-3.""" tr = Graph() for v in graph.vertex_keys(): tr.add_vertex(Vertex(v)) for u in graph.vertex_keys(): for v, weight in graph.get_vertex(u).successors(): tr.add_edge(v, u, weight) return tr
def graph_to_adj_matrix(graph: Graph): vertex_count = graph.vertex_len adj_matrix = [([0] * vertex_count) for _ in range(vertex_count)] for u in graph.vertex_keys(): for v, _ in graph.get_vertex(u).successors(): adj_matrix[u][v] = 1 return adj_matrix
def scc_tarjan(graph: Graph) -> List[List]: sccs = [] cache = TarjanCache() time = TimeCounter() for v_key in graph.vertex_keys(): if v_key not in cache.discover_times: _tarjan_internal(graph, v_key, sccs, cache, time) return sccs
def euler_tour_undirected(graph: Graph) -> list: ret = [] if graph.vertex_len == 0: return ret for v_key in graph.vertex_keys(): ret.append(v_key) break ret, _ = _euler(graph, ret, 0) return ret
def bfs(graph: Graph, visit_func: Callable[[Any], bool]=None) -> Tuple[dict, dict]: open_set = deque() came_from = {} depths = {} visited = set() # Gray or black nodes if not visit_func: def visit_func(_): return True for v in graph.vertex_keys(): if v in visited: continue _bfs_internal(graph, v, visit_func, open_set, came_from, depths, visited) return came_from, depths
def dfs(graph: Graph, pre_visit_func: Callable[[Any], bool]=None, post_visit_func: Callable[[Any], bool]=None)\ -> DFSResult: """Ex. 22.3-7""" if not pre_visit_func: def pre_visit_func(_): return True if not post_visit_func: def post_visit_func(_): return True result = DFSResult() time = TimeCounter() for v in graph.vertex_keys(): if v not in result.discover_times and not dfs_internal( graph, v, pre_visit_func, post_visit_func, result, time): break return result