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 TestQueue(unittest.TestCase): def setUp(self): self.queue = Queue() self.queue.enqueue(1) self.queue.enqueue(2) self.queue.enqueue(3) self.empty_queue = Queue() def test_dequeue(self): assert self.queue.dequeue() == 1 assert self.queue.dequeue() == 2 assert self.queue.dequeue() == 3 assert_raises(IndexError, self.queue.dequeue) def test_enqueue(self): self.queue.enqueue(7) assert len(self.queue) == 4 def test_is_empty(self): assert self.empty_queue.is_empty() def test_peek(self): assert self.queue.peek() == self.queue.peek() assert self.queue.peek() == 1 assert len(self.queue) == 3 assert_raises(IndexError, self.empty_queue.peek)
def breadth_first_traversal(self) -> Iterator['BinaryNode']: """ Returns an iterator which traverses this subtree breadth first """ q = Queue([self]) while not q.is_empty(): node = q.dequeue() yield node if node.lnode: q.enqueue(node.lnode) if node.rnode: q.enqueue(node.rnode)
def contains_cycle(graph: UndirectedGraph) -> bool: """ Simple breadth first cycle detection for Undirected graphs """ graph = copy.deepcopy(graph) # type: Graph visited_nodes = set() queue = Queue() queue.enqueue(graph.get_vertices()[0]) while not queue.is_empty(): vertex = queue.dequeue() for neighbour in graph.get_successive_vertices(vertex): if neighbour in visited_nodes: return True visited_nodes.add(neighbour) queue.enqueue(neighbour) graph.delete_edge(vertex, neighbour) return False