def connected_components(graph): ''' Yields nodes in connected components one by one. ''' if graph.is_directed(): raise NotUndirectedGraph("Graph must be undirected!") visited = set() for node in graph: if node not in visited: component = {node, } for level_graph in bfs(graph, node): [component.update(level) for level in level_graph.values()] visited.update(component) yield component
def _get_children(tree, root): ''' Returns dict(children), list(levels), int(height) children[v] contains all children of v in the tree rooted at root. levels contains lists of nodes on each level, starting from root. ''' children = {} levels = [] for i, level_tree in enumerate(bfs(tree, root)): levels.append([node for node in level_tree]) for node in level_tree: if level_tree[node]: children[node] = list(level_tree[node]) return children, levels, i
def unweighted_shortest_paths(graph, start, edge_weight=1): ''' Returns (predecessors, distance). predecessors[node] is the node's predecessor in the shortest path. distance[node] is the length of the path, where each crossed edge adds edge_weight=1 to the distance. ''' if start not in graph: raise NodeNotFound( "Node {0} is not in the graph!".format(start)) predecessors, distance = {start: None}, {start: 0} for level_graph in bfs(graph, start): for parent in level_graph: for child in level_graph[parent]: predecessors[child] = parent distance[child] = distance[parent] + edge_weight return (predecessors, distance)
def test_bfs_with_digraph_missing_node(self): with self.assertRaises(NodeNotFound): list(bfs(self.digraph, 999))
def test_bfs_with_digraph(self): self.assertEqual(list(bfs(self.digraph, 1)), [{1: {2}}, {2: {3, 4}}, {3: set(), 4: set()}])
def test_bfs_with_graph(self): self.assertEqual(list(bfs(self.graph, 1)), [{1: {2}}, {2: {3, 7}}, {3: {5}, 7: {'Sofia'}}, {'Sofia': set(), 5: set()}])