def topological_sort(graph: DirectedGraph) -> List: """ Called Kahns algorithm Sorts the vertices of a graph in a topological order or raises an exception when the graph is cyclical :param graph: The graph to be sorted toplogically """ graph = copy.deepcopy(graph) sorted_nodes = [] nodes = Queue() # Add the nodes without incoming edges to the starting nodes for vertex in graph.get_vertices(): if not graph.has_incoming_edge(vertex): nodes.enqueue(vertex) # Keep removing nodes and edges while nodes with no incoming edges exist while not nodes.is_empty(): node = nodes.dequeue() sorted_nodes.append(node) for edge in graph.get_edges(node)[:]: graph.delete_edge(edge.a, edge.b) if not graph.has_incoming_edge(edge.b): nodes.enqueue(edge.b) if len(list(graph.get_all_edges())): raise RuntimeError('Graph is cyclical') return sorted_nodes
class TestGraph(unittest.TestCase): def setUp(self): self.undirected = UndirectedGraph() self.undirected.add_edge(1, 2, 2) self.undirected.add_edge(1, 3, 6) self.undirected.add_edge(2, 3, 3) self.undirected.add_edge(2, 4, 1) self.undirected.add_edge(3, 4, 1) self.undirected.add_edge(3, 5, 4) self.undirected.add_edge(4, 5, 6) self.directed = DirectedGraph() self.directed.add_edge(1, 2, 2) self.directed.add_edge(1, 3, 6) self.directed.add_edge(2, 3, 3) self.directed.add_edge(2, 4, 1) self.directed.add_edge(3, 4, 1) self.directed.add_edge(3, 5, 4) self.directed.add_edge(4, 5, 6) def test_get_edges(self): assert self.undirected.get_all_edges() == self.directed.get_all_edges() assert self.undirected.get_vertices() == self.directed.get_vertices() def test_directed_graph(self): assert len(self.directed.get_successive_vertices(4)) == 1 assert len(self.undirected.get_successive_vertices(4)) == 3 assert self.undirected.edge_exists(4, 3) assert not self.directed.edge_exists(4, 3) self.directed.delete_edge(4, 3) self.undirected.delete_edge(4, 3) assert len(self.directed.get_all_edges()) == len(self.undirected.get_all_edges()) + 1 def test_undirected_graph(self): g = UndirectedGraph()
class TestGraph(unittest.TestCase): def setUp(self): self.undirected = UndirectedGraph() self.undirected.add_edge(1, 2, 2) self.undirected.add_edge(1, 3, 6) self.undirected.add_edge(2, 3, 3) self.undirected.add_edge(2, 4, 1) self.undirected.add_edge(3, 4, 1) self.undirected.add_edge(3, 5, 4) self.undirected.add_edge(4, 5, 6) self.directed = DirectedGraph() self.directed.add_edge(1, 2, 2) self.directed.add_edge(1, 3, 6) self.directed.add_edge(2, 3, 3) self.directed.add_edge(2, 4, 1) self.directed.add_edge(3, 4, 1) self.directed.add_edge(3, 5, 4) self.directed.add_edge(4, 5, 6) def test_get_edges(self): assert self.undirected.get_all_edges() == self.directed.get_all_edges() assert self.undirected.get_vertices() == self.directed.get_vertices() def test_directed_graph(self): assert len(self.directed.get_successive_vertices(4)) == 1 assert len(self.undirected.get_successive_vertices(4)) == 3 assert self.undirected.edge_exists(4, 3) assert not self.directed.edge_exists(4, 3) self.directed.delete_edge(4, 3) self.undirected.delete_edge(4, 3) assert len(self.directed.get_all_edges()) == len( self.undirected.get_all_edges()) + 1 def test_undirected_graph(self): g = UndirectedGraph()