def dfs(self, vertex_set=None, raise_if_cyclic=False, enter_vertex=None, leave_vertex=None): """ dfs(self,vertex_set=None,raise_if_cyclic=False,enter_vertex=None, leave_vertex=None) -> (discovery, parent, finish) Performs a depth-first search on a graph and returns three dictionaries with relevant information. If vertex_set is not None, then it is used as the list of ids to perform the DFS on. See CLRS p. 541. enter_vertex, when present, is called just before visiting a vertex for the first time (and only once) with the vertex id as a parameter. leave_vertex, when present, is called just after visiting a vertex for the first time (and only once) with the vertex id as a parameter. """ if not vertex_set: vertex_set = self.vertices # Ugly ugly python # http://mail.python.org/pipermail/python-list/2006-April/378964.html # We cannot explicitly "del data": # http://www.python.org/dev/peps/pep-0227/ class Closure(object): def clear(self): del self.discovery del self.parent del self.finish del self.t # Straight CLRS p.541 data = Closure() data.discovery = {} # d in CLRS data.parent = {} # \pi in CLRS data.finish = {} # f in CLRS data.t = 0 (enter, leave, back, other) = xrange(4) # inspired by http://www.ics.uci.edu/~eppstein/PADS/DFS.py def handle(v, w, edgetype): data.t += 1 if edgetype == enter: data.discovery[v] = data.t if enter_vertex: enter_vertex(w) if v != w: data.parent[w] = v elif edgetype == leave: data.finish[w] = data.t if leave_vertex: leave_vertex(w) elif edgetype == back and raise_if_cyclic: raise self.GraphContainsCycles(v, w) visited = set() gray = set() # helper function to build stack structure def st(v): return (v, iter(self.adjacency_list[v])) for vertex in vertex_set: if vertex not in visited: handle(vertex, vertex, enter) visited.add(vertex) stack = Stack() stack.push(st(vertex)) gray.add(vertex) while stack.size: parent, children = stack.top() try: child, _ = children.next() if child in visited: handle(parent, child, (child in gray and back or other)) else: handle(parent, child, enter) visited.add(child) stack.push(st(child)) gray.add(child) except StopIteration: gray.remove(parent) stack.pop() if stack.size: handle(stack.top()[0], parent, leave) handle(vertex, vertex, leave) result = (data.discovery, data.parent, data.finish) data.clear() return result
def dfs(self, vertex_set=None, raise_if_cyclic=False, enter_vertex=None, leave_vertex=None): """ dfs(self,vertex_set=None,raise_if_cyclic=False,enter_vertex=None, leave_vertex=None) -> (discovery, parent, finish) Performs a depth-first search on a graph and returns three dictionaries with relevant information. If vertex_set is not None, then it is used as the list of ids to perform the DFS on. See CLRS p. 541. enter_vertex, when present, is called just before visiting a vertex for the first time (and only once) with the vertex id as a parameter. leave_vertex, when present, is called just after visiting a vertex for the first time (and only once) with the vertex id as a parameter. """ if not vertex_set: vertex_set = self.vertices # Straight CLRS p.541 discovery = {} # d in CLRS parents = {} # \pi in CLRS finish = {} # f in CLRS t = [0] (enter, leave, back, other) = xrange(4) # inspired by http://www.ics.uci.edu/~eppstein/PADS/DFS.py def handle(v, w, edgetype): t[0] += 1 if edgetype == enter: discovery[v] = t[0] if enter_vertex: enter_vertex(w) if v != w: parents[w] = v elif edgetype == leave: finish[w] = t[0] if leave_vertex: leave_vertex(w) elif edgetype == back and raise_if_cyclic: raise GraphContainsCycles(v, w) visited = set() gray = set() # helper function to build stack structure def st(v): return (v, iter(self.adjacency_list[v])) for vertex in vertex_set: if vertex not in visited: handle(vertex, vertex, enter) visited.add(vertex) stack = Stack() stack.push(st(vertex)) gray.add(vertex) while stack.size: parent, children = stack.top() try: child, _ = children.next() if child in visited: handle(parent, child, (child in gray and back or other)) else: handle(parent, child, enter) visited.add(child) stack.push(st(child)) gray.add(child) except StopIteration: gray.remove(parent) stack.pop() if stack.size: handle(stack.top()[0], parent, leave) handle(vertex, vertex, leave) return discovery, parents, finish