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
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)