def all_shortest_paths_by_length(self, v1, v2, aggregate_fn=None, *args, **kwargs): q = Queue() q.enqueue((v1, [], 0)) # Maximum number of vertices wont exceed the number of vertices # if there are cycles, they'd not be included more than once in the path shortest_path_level = self.vertices while q: curr_vertex, curr_prefix, level = q.dequeue() # Found all the shortest paths if level > shortest_path_level: return # found destination vertex, # record this path as one of the paths if curr_vertex == v2: path = curr_prefix + [v2] shortest_path_level = level aggregate_fn(path, *args, **kwargs) for v,_ in self._adjlists[curr_vertex]: # visited[] traking doesn't yield well to BFS # when extracting all paths # Instead just check if we don't add a vertex already # in the current path so we don't loop endlessly # if there's a cycle / its an undirected graph if v not in curr_prefix: q.enqueue((v, curr_prefix + [curr_vertex], level+1))
def top_view(self, aggregate_fn=_default_printfn, **kwargs): if not self.root: return q = Queue() min_width = 0 max_width = 0 q.enqueue((0, self.root)) # Top-view begins with the root node aggregate_fn(kwargs, self.root.value) while q.length() != 0: width, node = q.dequeue() if width < min_width: min_width = width aggregate_fn(kwargs, node.value) elif width > max_width: max_width = width aggregate_fn(kwargs, node.value) # NOTE: width 0, is root, would already be filled in at root, # and in a top-view is not going to replaced q.enqueue((width - 1, node.left)) if node.left else None q.enqueue((width + 1, node.right)) if node.right else None
def width(self): if not self.root: return 0 q = Queue() q.enqueue((0, self.root)) curr_level = 0 curr_level_nodes = 0 max_width = 0 while q.length() != 0: level, node = q.dequeue() q.enqueue((level + 1, node.left)) if node.left else None q.enqueue((level + 1, node.right)) if node.right else None # Start of a new level # Check if number of nodes at previous level > mqx nodes at any level if level != curr_level: if curr_level_nodes > max_width: max_width = curr_level_nodes # start counting nodes for the current level curr_level_nodes = 0 curr_level_nodes += 1 curr_level = level # Check last level if curr_level_nodes > max_width: max_width = curr_level_nodes return max_width
def levelorder_traversal(self, aggregate_fn=_default_printfn, **kwargs): if not self.root: return q = Queue() q.enqueue(self.root) while q.length() != 0: tmp = q.dequeue() aggregate_fn(kwargs, tmp.value) q.enqueue(tmp.left) if tmp.left else None q.enqueue(tmp.right) if tmp.right else None
def bfs(adjacency_lists, startvertex, visited, aggregate_fn, *args, **kwargs): neighbors = Queue() neighbors.enqueue(startvertex) visited[startvertex] = True while neighbors: v = neighbors.dequeue() aggregate_fn(v, *args, **kwargs) # enqueue all vertices that are neighbors of v for n,_ in adjacency_lists[v]: if not visited[n]: visited[n] = True neighbors.enqueue(n)
def bfs(adjacency_matrix, startvertex, visited, aggregate_fn, *args, **kwargs): neighbors = Queue() visited[startvertex] = True neighbors.enqueue(startvertex) while neighbors: v = neighbors.dequeue() aggregate_fn(v, *args, **kwargs) # enqueue all vertices that are neighbors of v for n in xrange(len(visited)): if adjacency_matrix[v][n] is not None and not visited[n]: visited[n] = True neighbors.enqueue(n)
def top_view_LR(self, aggregate_fn=_default_printfn, **kwargs): if not self.root: return # Queue to help with level-order traversal q = Queue() # Store L/R width of a node and its value if it is visible in the top-view, in a sorted list # ordered by the width # at the end of the level-order traversal the list would contain # [(-max_left_width, node value), ...., (0, root.value), ... (max_right_width, node value)] slist = SLL() # pairs a(w1, node_val1) vs b(w2, node_val2) are valued against each other # depending on w1 vs w2 (where w1 and w2 are widths, so slist is kept sorted by the nodes' L/R widths) pair_comparator = lambda (w1, node_val1), (w2, node_val2): cmp(w1, w2) min_width = 0 max_width = 0 q.enqueue((0, self.root)) # Top-view begins with the root node slist.place((0, self.root.value)) while q.length() != 0: width, node = q.dequeue() if width < min_width: min_width = width slist.place((width, node.value)) elif width > max_width: max_width = width slist.place((width, node.value)) # NOTE: width 0, is root, would already be filled in at root, # and in a top-view is not going to replaced q.enqueue((width - 1, node.left)) if node.left else None q.enqueue((width + 1, node.right)) if node.right else None # At the end of the level-order traversal, # slist is ordered by width, so # (-max_left_width, ..., 0, ..., max_right_width) # Just retrieve the SLL L-R for the top view (L-R) while slist.size != 0: width, item = slist.pop_front() aggregate_fn(kwargs, item)
def left_view(self, aggregate_fn=_default_printfn, **kwargs): if not self.root: return q = Queue() levels_done = None q.enqueue((0, self.root)) while q.length() != 0: curr_level, node = q.dequeue() # Nothing has been printed in this level so far # NOTE: (None < 0) in python if curr_level > levels_done: aggregate_fn(kwargs, node.value) levels_done = curr_level q.enqueue((curr_level + 1, node.left)) if node.left else None q.enqueue((curr_level + 1, node.right)) if node.right else None
def span(self): if not self.root: return 0 q = Queue() min_width = 0 max_width = 0 q.enqueue((0, self.root)) while q.length() != 0: width, node = q.dequeue() if width < min_width: min_width = width elif width > max_width: max_width = width q.enqueue((width - 1, node.left)) if node.left else None q.enqueue((width + 1, node.right)) if node.right else None return max_width - min_width
def bottom_view(self, aggregate_fn=_default_printfn, **kwargs): if not self.root: return q = Queue() # A hash table that stores a map of L/R width to a node's item # We traverse the tree in level-order, and keep replacing slist[width] if we find a new node with the same width # At the end of the traversal, every slist[width] from {-max_left_width, ..., 0, ..., max_right_width} will contain the # node items that would be visible from a bottom view of the binary tree slist = {} min_width = 0 max_width = 0 q.enqueue((0, self.root)) # Star with placing root at width 0 slist[0] = self.root.value while q.length() != 0: width, node = q.dequeue() # As we traverse level-by-level, keep replacing # item at L/R width slist[width] = node.value # Track max_left_width, max_right_width # so we don't need to sort the hash table slist, # Just retrieve slist[{-max_left_width, ..., 0, ..., max_right_width}] if width < min_width: min_width = width elif width > max_width: max_width = width q.enqueue((width - 1, node.left)) if node.left else None q.enqueue((width + 1, node.right)) if node.right else None # At the end of the level-order traversal, # Just 'aggregate' slist[{-max_left_width, ..., 0, ..., max_right_width}] for i in range(min_width, max_width + 1): aggregate_fn(kwargs, slist[i])
def paths_2(self, v1, v2, aggregate_fn=None, *args, **kwargs): if not aggregate_fn: aggregate_fn = Graph._default_printfn q = Queue() q.enqueue((v1, [])) while q: curr_vertex, curr_prefix = q.dequeue() # found destination vertex, # record this path as one of the paths if curr_vertex == v2: aggregate_fn(curr_prefix + [v2], *args, **kwargs) for v,_ in self._adjlists[curr_vertex]: # visited[] traking doesn't yield well to BFS # when extracting all paths # Instead just check if we don't add a vertex already # in the current path so we don't loop endlessly # if there's a cycle / its an undirected graph if v not in curr_prefix: q.enqueue((v, curr_prefix + [curr_vertex]))
def shortest_path_by_length(self, v1, v2): q = Queue() retrace = {} q.enqueue(v1) retrace[v1] = None def retrace_path(retrace): path = [] v = v2 while v is not None: path.insert(0, v) v = retrace[v] return path # Start a BFS traversal while q: curr_vertex = q.dequeue() # found destination vertex, # retrace from last vertex using the mapping all the way to v1 if curr_vertex == v2: return retrace_path(retrace) for v,_ in self._adjlists[curr_vertex]: # visited[] traking doesn't yield well to BFS # when extracting all paths # Instead just check if we don't add a vertex already # in the current path so we don't loop endlessly # if there's a cycle / its an undirected graph if not retrace.has_key(v): q.enqueue(v) retrace[v] = curr_vertex return []
def right_view(self, aggregate_fn=_default_printfn, **kwargs): if not self.root: return q = Queue() q.enqueue((0, self.root)) while q.length() != 0: curr_level, node = q.dequeue() q.enqueue((curr_level + 1, node.left)) if node.left else None q.enqueue((curr_level + 1, node.right)) if node.right else None # peek next node in the queue to see if this is the last node in the current level # if yes, print it try: (level, next_entry) = q.front() except UnderFlowError: (level, next_entry) = (None, None) # Queue is either empty, in which case this is the rightmost node in the last level # *OR*, next entry in the queue is for the level after this one, so this is the rightmost in the current level # In both cases, current node would be visible in a right-view. if (not next_entry) or (level > curr_level): aggregate_fn(kwargs, node.value)
def __init__(self): self.q = Queue() self.min = None
def __init__(self): self.q1 = Queue() self.q2 = Queue()
def __init__(self): self.q1 = Queue() self.dq2 = Deque() self.min = None
def __init__(self): self.q = Queue()