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))
class QueueMin(object): def __init__(self): self.q = Queue() self.min = None # All queue items are always in Q, def __len__(self): return self.q.size def __repr__(self): return "{%r}/Min: %r" % (self.q, self.min) def __str__(self): return str(self.q) def minimum(self): return self.min # Add to Q and return def enqueue(self, x): self.q.enqueue(x) # update min # if min is None => this is the first item to be enqueued self.min = min(x, self.min) if self.min else x # Dequeue() from Q # if popped item was minima, Re-enqueue all items while calculating new minima def dequeue(self): # Helper function to re-enqueue all items from Queue, Q back into itself # while updating new minima def reenqueue(q): minima = q.front() for i in range(len(q)): x = q.dequeue() q.enqueue(x) minima = min(x, minima) return minima # SLL raises UnderFlowError if Q is empty item = self.q.dequeue() # We just dequeued the last item from the queue # restore min to be None if not self.q: self.min = None elif item == self.min: # Update min if item == minima self.min = reenqueue(self.q) return item # Return the front of Q def front(self): return self.q.front() # Return the back of Q def back(self): return self.q.back()
class Stack(object): def __init__(self): self.q1 = Queue() self.q2 = Queue() # peek what's at the top of the stack # New items are always added to Q1's end # Stack's top would be at the back of Q1 def top(self): return self.q1.back() def __len__(self): return self.q1.size # Just add to Q1 and return def push(self, x): self.q1.enqueue(x) # Move (n-1) items from q1 to q2 # dequeue remaining item from q1 to return # swap q1, q2 def pop(self): # Helper function to move 'n' items from queue a to queue b def move(a, b, n): for i in range(n): b.enqueue(a.dequeue()) # Move (n-1) items from q1 to q2 move(self.q1, self.q2, self.q1.size-1) # Swap Q1, Q2 self.q1, self.q2 = self.q2, self.q1 # Dequeue and return the last item from what was q1 earlier, and now q2 return self.q2.dequeue() def __str__(self): slist = [] for x in self.q1: slist.insert(0, str(x)) return '[%d]: ' %(self.__len__()) + ' '.join(slist) def __repr__(self): return "{%r , %r}" %(self.q1, self.q2)
def bfs_i(adjacency_lists, startvertex, visited, aggregate_fn, *args, **kwargs): neighbors = Queue() neighbors.enqueue(startvertex) while neighbors: v = neighbors.dequeue() if not visited[v]: visited[v] = True aggregate_fn(v, *args, **kwargs) # enqueue all vertices that are neighbors of v for n,_ in adjacency_lists[v]: if not visited[n]: neighbors.enqueue(n)
def bfs_i(adjacency_matrix, startvertex, visited, aggregate_fn, *args, **kwargs): neighbors = Queue() neighbors.enqueue(startvertex) while neighbors: v = neighbors.dequeue() if not visited[v]: visited[v] = True 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]: neighbors.enqueue(n)
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)
class Stack(object): def __init__(self): self.q = Queue() # peek what's at the top of the stack # New items are always added to Q's end # Stack's top would be at the back of Q def top(self): return self.q.back() def __len__(self): return self.q.size # Just add to Q and return def push(self, x): self.q.enqueue(x) # re-enqueue (n-1) items from Q, and re-enqueue back to Q def pop(self): # Helper function to reenqueue 'n' items from queue a back into it def reenqueue(a, n): for i in range(n): a.enqueue(a.dequeue()) # reenqueue (n-1) items from q reenqueue(self.q, self.q.size-1) # Dequeue from the front of q return self.q.dequeue() # Actual stack order would be the q in reverse order def __str__(self): slist = [] for x in self.q: slist.insert(0, str(x)) return '[%d]: ' %(self.__len__()) + ' '.join(slist) def __repr__(self): return "%r" %(self.q)
class Stack(object): def __init__(self): self.q1 = Queue() self.q2 = Queue() # peek what's at the top of the stack # Stack-order is preserved in Q1 # Stack's top would be at the front of Q1 def top(self): return self.q1.front() def __len__(self): return self.q1.size # Add x to Q2 # Move everything from Q1 to Q2, so Q2 preserves stack-order # swap Q1, Q2 def push(self, x): # Helper function to move all items from queue a to queue b def move(a, b): while a: b.enqueue(a.dequeue()) self.q2.enqueue(x) # Move items from q1 to q2 move(self.q1, self.q2) # Swap Q1, Q2 self.q1, self.q2 = self.q2, self.q1 # Q1 has items in stack-order # Just dequeue from Q1 and return def pop(self): return self.q1.dequeue() def __str__(self): return str(self.q1) def __repr__(self): return "{%r , %r}" %(self.q1, self.q2)
class Stack(object): def __init__(self): self.q1 = Queue() self.q2 = Queue() # peek what's at the top of the stack # New items are always added to Q1's end # Stack's top would be at the back of Q1 def top(self): return self.q1.back() def __len__(self): return self.q1.size # Just add to Q1 and return def push(self, x): self.q1.enqueue(x) # Move (n-1) items from q1 to q2 # dequeue remaining item from q1 to return # swap q1, q2 def pop(self): # Helper function to move 'n' items from queue a to queue b def move(a, b, n): for i in range(n): b.enqueue(a.dequeue()) # Move (n-1) items from q1 to q2 move(self.q1, self.q2, self.q1.size - 1) # Swap Q1, Q2 self.q1, self.q2 = self.q2, self.q1 # Dequeue and return the last item from what was q1 earlier, and now q2 return self.q2.dequeue() def __str__(self): slist = [] for x in self.q1: slist.insert(0, str(x)) return '[%d]: ' % (self.__len__()) + ' '.join(slist) def __repr__(self): return "{%r , %r}" % (self.q1, self.q2)
class Stack(object): def __init__(self): self.q = Queue() # peek what's at the top of the stack # Stack-order is preserved in Q # Stack's top would be at the front of Q def top(self): return self.q.front() def __len__(self): return self.q.size # Enqueue x into Q # re-enqueue (n-1) items from Q, and re-enqueue back to Q def push(self, x): # Helper function to reenqueue 'n' items from queue a back into it def reenqueue(a, n): for i in range(n): a.enqueue(a.dequeue()) self.q.enqueue(x) # reenqueue (n-1) items from q reenqueue(self.q, self.q.size-1) # Just dequeue from Q as it preserves stack-order def pop(self): # Dequeue from the front of q return self.q.dequeue() # Q preserves stack-order, Just return Q as-is def __str__(self): return str(self.q) def __repr__(self): return "%r" %(self.q)
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 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
class Stack(object): def __init__(self): self.q = Queue() # peek what's at the top of the stack # New items are always added to Q's end # Stack's top would be at the back of Q def top(self): return self.q.back() def __len__(self): return self.q.size # Just add to Q and return def push(self, x): self.q.enqueue(x) # re-enqueue (n-1) items from Q, and re-enqueue back to Q def pop(self): # Helper function to reenqueue 'n' items from queue a back into it def reenqueue(a, n): for i in range(n): a.enqueue(a.dequeue()) # reenqueue (n-1) items from q reenqueue(self.q, self.q.size - 1) # Dequeue from the front of q return self.q.dequeue() # Actual stack order would be the q in reverse order def __str__(self): slist = [] for x in self.q: slist.insert(0, str(x)) return '[%d]: ' % (self.__len__()) + ' '.join(slist) def __repr__(self): return "%r" % (self.q)
class Stack(object): def __init__(self): self.q1 = Queue() self.q2 = Queue() # peek what's at the top of the stack # Stack-order is preserved in Q1 # Stack's top would be at the front of Q1 def top(self): return self.q1.front() def __len__(self): return self.q1.size # Add x to Q2 # Move everything from Q1 to Q2, so Q2 preserves stack-order # swap Q1, Q2 def push(self, x): # Helper function to move all items from queue a to queue b def move(a, b): while a: b.enqueue(a.dequeue()) self.q2.enqueue(x) # Move items from q1 to q2 move(self.q1, self.q2) # Swap Q1, Q2 self.q1, self.q2 = self.q2, self.q1 # Q1 has items in stack-order # Just dequeue from Q1 and return def pop(self): return self.q1.dequeue() def __str__(self): return str(self.q1) def __repr__(self): return "{%r , %r}" % (self.q1, self.q2)
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 []
class Stack(object): def __init__(self): self.q = Queue() # peek what's at the top of the stack # Stack-order is preserved in Q # Stack's top would be at the front of Q def top(self): return self.q.front() def __len__(self): return self.q.size # Enqueue x into Q # re-enqueue (n-1) items from Q, and re-enqueue back to Q def push(self, x): # Helper function to reenqueue 'n' items from queue a back into it def reenqueue(a, n): for i in range(n): a.enqueue(a.dequeue()) self.q.enqueue(x) # reenqueue (n-1) items from q reenqueue(self.q, self.q.size - 1) # Just dequeue from Q as it preserves stack-order def pop(self): # Dequeue from the front of q return self.q.dequeue() # Q preserves stack-order, Just return Q as-is def __str__(self): return str(self.q) def __repr__(self): return "%r" % (self.q)
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 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 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)
class QueueMin(object): def __init__(self): self.q1 = Queue() self.q2 = Queue() self.min = None # All queue items are always in Q1, Q2 is merely used to move queue elements and update minima # after which Q2 is renamed Q1 def __len__(self): return self.q1.size def __repr__(self): return "{%r , %r}/Min: %r" % (self.q1, self.q2, self.min) def __str__(self): return str(self.q1) def minimum(self): return self.min # Add to Q1 and return def enqueue(self, x): self.q1.enqueue(x) # update min # if min is None => this is the first item to be enqueued self.min = min(x, self.min) if self.min else x # Dequeue() from Q2 # if popped item was minima, use Q2 to move all items while calculating new minima def dequeue(self): # Helper function to move all items from Queue, A to Queue, B # while updating new minima def move(a, b): minima = a.front() while a: x = a.dequeue() b.enqueue(x) minima = min(x, minima) return minima # SLL raises UnderFlowError if Q2 is empty item = self.q1.dequeue() # We just dequeued the last item from the queue # restore min to be None if not self.q1: self.min = None elif item == self.min: # Update min if item == minima self.min = move(self.q1, self.q2) # swap Q1, Q2 self.q1, self.q2 = self.q2, self.q1 return item # Return the front of Q1 def front(self): return self.q1.front() # Return the back of Q1 def back(self): return self.q1.back()
class QueueMin(object): def __init__(self): self.q1 = Queue() self.dq2 = Deque() self.min = None # All queue items are always in Q1, # DQ2 is merely used to store relative order of minimas def __len__(self): return self.q1.size def __repr__(self): return "{%r , %r}/Min: %r" %(self.q1, self.dq2, self.min) def __str__(self): return str(self.q1) def minimum(self): return self.min # Add item to Q1 def enqueue(self, x): self.q1.enqueue(x) # update min # if min is None => this is the first item to be enqueued self.min = min(x, self.min) if self.min else x # Update DQ2 to maintain the order of minimas, # so when a minima is removed, the next minima can be immediately retrieved # remove everything from the back of DQ2 as long as it is > item x while self.dq2 and self.dq2.back() > x: self.dq2.pop_back() # Add item x to DQ2 self.dq2.push_back(x) # Dequeue() from Q1 # DQ2 stores relative order of minimas for the current queue items # if popped item was minima, update minima to DQ2 new head() def dequeue(self): # SLL raises UnderFlowError if Q2 is empty item = self.q1.dequeue() # item removed was the current minima, remove it from DQ2 as well # item would be found in the head of DQ2 if item == self.min: self.dq2.pop_front() # Also, update new min which would be the new head of DQ2 after removing the current minima # NOTE: self.min should be None, if dq2 is empty - ie, we just removed the last item in the Queue self.min = self.dq2.front() if self.dq2 else None return item # Return the front of Q1 def front(self): return self.q1.front() # Return the back of Q1 def back(self): return self.q1.back()
class QueueMin(object): def __init__(self): self.q = Queue() self.min = None # All queue items are always in Q, def __len__(self): return self.q.size def __repr__(self): return "{%r}/Min: %r" %(self.q, self.min) def __str__(self): return str(self.q) def minimum(self): return self.min # Add to Q and return def enqueue(self, x): self.q.enqueue(x) # update min # if min is None => this is the first item to be enqueued self.min = min(x, self.min) if self.min else x # Dequeue() from Q # if popped item was minima, Re-enqueue all items while calculating new minima def dequeue(self): # Helper function to re-enqueue all items from Queue, Q back into itself # while updating new minima def reenqueue(q): minima = q.front() for i in range(len(q)): x = q.dequeue() q.enqueue(x) minima = min(x, minima) return minima # SLL raises UnderFlowError if Q is empty item = self.q.dequeue() # We just dequeued the last item from the queue # restore min to be None if not self.q: self.min = None elif item == self.min: # Update min if item == minima self.min = reenqueue(self.q) return item # Return the front of Q def front(self): return self.q.front() # Return the back of Q def back(self): return self.q.back()