Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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
Ejemplo n.º 7
0
    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])
Ejemplo n.º 8
0
    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)