def test_complicated():
    tree = TreeNode(50)
    tree.insert(25)
    tree.insert(30)
    tree.insert(27)
    tree.insert(26)
    tree.insert(60)
    tree.insert(70)
    assert tree.balance() == 2
    tree = tree.rebalance(tree)
    assert tree.balance() == 1
Exemple #2
0
 def _put(self, key, val, currentNode):
     if key < currentNode.key :
         if currentNode.hasLeftChild() :
             self._put(key, val, currentNode.leftChild)
         else :
             currentNode.leftChild = TreeNode(key, val, parent = currentNode)
             self.updateBalance(currentNode.leftChild)
     else :
         if currentNode.hasRightChild() :
             self._put(key, val, currentNode.rightChild)
         else :
             currentNode.rightChild = TreeNode(key, val, parent = currentNode)
             self.updateBalance(currentNode.rightChild)
def test_insert_and_size():
    tree = TreeNode(0)
    assert tree.size() == 1
    tree.insert(1)
    assert tree.size() == 2
    tree.insert(1)
    assert tree.size() == 2
def test_right_linked_list_four():
    tree = TreeNode(0)
    tree.insert(1)
    tree.insert(2)
    tree.insert(3)
    assert tree.balance() == -3
    tree = tree.rebalance(tree)
    assert tree.balance() == 1
Exemple #5
0
def test_node_exists_args():
    """Test Create a Tree Node."""
    from bst import TreeNode

    test_node = TreeNode(1, 2, 3)

    assert test_node
def test_left_linked_list_four():
    tree = TreeNode(3)
    tree.insert(2)
    tree.insert(1)
    tree.insert(0)
    assert tree.balance() == 3
    assert tree.val == 3
    tree = tree.rebalance(tree)
    assert tree.balance() == -1
    assert tree.val == 1
def test_left_linked_list():
    tree = TreeNode(2)
    tree.insert(1)
    tree.insert(0)
    assert tree.balance() == 2
    tree = tree.rebalance(tree)
    assert tree.balance() == 0
    treelist = [n for n in tree.depth_traversal("in")]
    assert treelist == [0, 1, 2]
Exemple #8
0
 def insert(self, value):
     # insert new node
     tmp_node = super()._insert(value)
     # create new TreeNode with red color
     new_node = TreeNode(value) #red by default
     parent = tmp_node.get_parent()
     # take care of node-parent connection
     if not parent or value == parent.get_data():
         return
     elif value > parent.get_data():
         parent.set_right(new_node)
     elif value < parent.get_data():
         parent.set_left(new_node)
     # recolor starting from new_node till root
     self.root = self.__recolor(new_node)
     # root is black (isn't essential tho!!)
     self.root.set_color(Color.BLACK)
    ######################### INSERTION #########################
    def insert(self, value):
        _ = super()._insert(value)
        self.rebalance()

    ######################### REMOVAL #########################
    def remove(self, del_value):
        _ = super()._remove(del_value)
        self.rebalance()


if __name__ == "__main__":
    # to test left rotation
    avl = AVL(22)
    avl.root.set_right(TreeNode(43))
    avl.root.set_left(TreeNode(18))
    avl.root.get_left().set_left(TreeNode(9))
    avl.root.get_left().set_right(TreeNode(21))
    avl.root.get_left().get_left().set_left(TreeNode(6))
    avl.root.get_left().get_left().get_left().set_left(TreeNode(0))
    print(avl, '\n')
    avl.rebalance()
    print(avl)
    print('=' * 50)

    #######################################
    # to test left-right rotation
    avl = AVL(78)
    avl.root.set_right(TreeNode(88))
    avl.root.set_left(TreeNode(50))
Exemple #10
0
 def __init__(self, value):
     if isinstance(value, TreeNode):
         self.root = value
     else:
         self.root = TreeNode(value)
     self.root.set_color(Color.BLACK)
Exemple #11
0
class RedBlackTree(BST):
    def __init__(self, value):
        if isinstance(value, TreeNode):
            self.root = value
        else:
            self.root = TreeNode(value)
        self.root.set_color(Color.BLACK)


    ############################## HEIGHT ##############################
    def get_black_height(self):
        #TODO
        pass

    ############################## ROTATION ##############################
    def __rotate_left(self, start_node):
        # print("Rotating Left")
        middle = start_node.get_right()
        middle.set_parent( start_node.get_parent() )
        start_node.set_right(middle.get_left())
        middle.set_left(start_node)
        return middle

    def __rotate_right(self, start_node):
        # print("Rotating Right")
        middle = start_node.get_left()
        middle.set_parent( start_node.get_parent() )
        start_node.set_left(middle.get_right())
        middle.set_right(start_node)
        return middle


    ############################## INSERTION ##############################
    def __recolor_case3(self, start_node):
        # get basic info
        uncle = start_node.get_uncle()
        parent = start_node.get_parent()
        grandparent = parent.get_parent() if parent else None
        # parent is left-child and start_node is left-child
        if parent.is_left_child() and start_node.is_left_child():
            grandparent.set_color(Color.RED)
            parent.set_color(Color.BLACK)
            grandparent = self.__rotate_right(grandparent)
        # parent is left-child and start_node is right-child
        elif parent.is_left_child() and not start_node.is_left_child():
            # first rotation
            parent = self.__rotate_left(parent)
            grandparent.set_left(parent)
            grandparent.set_color(Color.RED)
            # second rotation
            grandparent = self.__rotate_right(grandparent)
            grandparent.set_color(Color.BLACK)
        # parent is right-child and start_node is left-child
        elif not parent.is_left_child() and start_node.is_left_child():
            # first rotation
            parent = self.__rotate_right(parent)
            grandparent.set_right(parent)
            grandparent.set_color(Color.RED)
            # second rotation
            grandparent = self.__rotate_left(grandparent)
            grandparent.set_color(Color.BLACK)
        # parent is right-child and start_node is right-child
        else:
            grandparent.set_color(Color.RED)
            parent.set_color(Color.BLACK)
            grandparent = self.__rotate_left(grandparent)
        return grandparent

    def __recolor(self, start_node):
        """
        Recoloring can be done according to these three cases:
        - case I:   parent is 'black'
        - case II:  parent is 'red' and uncle is 'red'
        - case III: parent is 'red' and uncle is 'black'
        """
        # get basic info
        uncle = start_node.get_uncle()
        parent = start_node.get_parent()
        grandparent = parent.get_parent() if parent else None
        # recolor when node has a grandparent
        if parent is None or grandparent is None:
            return parent if parent else start_node

        # case I
        if parent.get_color() == Color.BLACK:
            #do nothing
            # print("Case I")
            return self.root
        else:
            # case II
            if uncle and uncle.get_color() == Color.RED:
                # print("Case II")
                parent.set_color(Color.BLACK)
                uncle.set_color(Color.BLACK)
                grandparent.set_color(Color.RED)
            # case III
            else:
                # print("Case III")
                # get great grandparent
                great_grandparent = grandparent.get_parent()
                grandparent = self.__recolor_case3(start_node)
                # set connection
                if great_grandparent:
                    if great_grandparent.data > grandparent.get_data():
                        great_grandparent.set_left(grandparent)
                    else:
                        great_grandparent.set_right(grandparent)
            # recursively do the same over grandparent 
            return self.__recolor(grandparent)

    def insert(self, value):
        # insert new node
        tmp_node = super()._insert(value)
        # create new TreeNode with red color
        new_node = TreeNode(value) #red by default
        parent = tmp_node.get_parent()
        # take care of node-parent connection
        if not parent or value == parent.get_data():
            return
        elif value > parent.get_data():
            parent.set_right(new_node)
        elif value < parent.get_data():
            parent.set_left(new_node)
        # recolor starting from new_node till root
        self.root = self.__recolor(new_node)
        # root is black (isn't essential tho!!)
        self.root.set_color(Color.BLACK)


    ############################## REMOVAL ##############################
    def _find_replacement(self, start_node):
        """
        NOTE: Here, we're tyring to exploit two characteristics of Red-black
        trees and they are: 
            - red-nodes are good replacements.
            - when removing a red node, there must be at least one red-node as
              a replacement at least.
        """
        if start_node.is_leaf():
            replacement_node = None
        else:
            # in-order successor
            successor = super()._get_min_node(start_node.get_right()) \
                if start_node.get_right() else None
            # in-order predecessor
            predecessor = super()._get_max_node(start_node.get_left()) \
                if start_node.get_left() else None
            # find the red-node
            if successor and successor.get_color() == Color.RED:
                replacement_node = successor
            elif predecessor and predecessor.get_color() == Color.RED:
                replacement_node = predecessor
            else:
                replacement_node = successor if successor else predecessor
        return replacement_node


    def __get_node_and_replacement(self, del_value, start_node):
        #TODO: try to get rid of this function and use find() or search instead.
        curr_value = start_node.get_data()
        # when del_value is found
        if del_value == curr_value:
            replacement = self._find_replacement(start_node)
            return start_node, replacement
        # search left-side
        elif del_value < curr_value:
            if start_node.get_left() is None:
                # raise ValueError("Couldn't find given value in the tree!!")
                return start_node, None
            else:
                return self.__get_node_and_replacement(del_value,
                                                       start_node.get_left())
        # search right-side
        else:
            if start_node.get_right() is None:
                # raise ValueError("Couldn't find given value in the tree!!")
                return start_node, None
            else:
                return self.__get_node_and_replacement(del_value,
                                                       start_node.get_right())


    def __transplant(self, node, replacement):
        parent = node.get_parent()
        if replacement is None:
            if parent is None:
                self.__transplant(replacement, None)
                node.data = replacement.data
                return parent, node
            else:
                if node.is_left_child():
                    parent.set_left(replacement)
                    return parent, parent.get_left()
                else:
                    parent.set_right(replacement)
                    return parent, parent.get_right()
        else:
            if replacement.is_leaf():
                new_replacement = None
            elif replacement.get_left():
                new_replacement = replacement.get_left()
            else:
                new_replacement = replacement.get_right()
            # transplant data & color
            node.data = replacement.data
            node.set_color(replacement.get_color())
            self.__transplant(replacement, new_replacement)
            return parent, node

    
    def __handle_double_black_case1(self, parent, double_black_node):
        pass
    
    def __handle_double_black_case2(self, parent, double_black_node, sibling):
        parent.set_color(Color.RED)
        sibling.set_color(Color.BLACK)
        if sibling.is_left_child():
            parent = self.__rotate_right(parent)
        else:
            parent = self.__rotate_left(parent)
        return parent

    def __handle_double_black_case3(self, parent, double_black_node, sibling):
            sibling.set_color(Color.RED)
            grandparent = parent.get_parent()
            if 

    def __handle_double_black_case4(self, parent, double_black_node):
        pass

    def __handle_double_black_case5(self, parent, double_black_node):
        pass

    def __handle_double_black_case6(self, parent, double_black_node):
        pass
    
    def __handle_double_black(self, parent, double_black_node):
        """
        SRC: https://en.wikipedia.org/wiki/Red%E2%80%93black_tree
        When dealing with double black nodes, we have six cases to consider:
        Case I  : if double_black_node is root
        Case II : (s) is red
        Case III: (p) and (s) are black and the two children of (s) are black
        Case IV : (p) is red, (s) is black and the two children of (s) are black
        Case V  : (s) is black, left-child of (s) is red, right-child of (s) is
                  black and (s) is the right-child
        Case VI : (s) is black, right-child of (s) is red, and (s) is the right-
                  child
        
        Note: (s) is the sibling of the double_black_node and (p) is the parent
        """
         # Case I
        if parent is None:
            return double_black_node
        else:
            grandparent = parent.get_parent()
            sibling = double_black_node.get_sibling() \
                    if double_black_node \
                    else parent.get_left() \
                        if parent.get_left() else parent.get_right()
            print("sibling:", sibling)
            if sibling is None:
                pass
            else:
                s_left_child = sibling.get_left()
                s_right_child = sibling.get_right()
                # get colors of sibling's children
                s_left_color = s_left_child.get_color() if s_left_child \
                                                        else Color.BLACK
                s_right_color = s_right_child.get_color() if s_right_child \
                                                          else Color.BLACK
                # Case II
                if sibling.get_color() == Color.RED:
                    parent = self.__handle_double_black_case2(parent,
                                                            double_black_node)
                # Case III
                elif (parent.get_color() == Color.BLACK and
                    sibling.get_color() == Color.BLACK and
                    s_left_color == Color.BLACK and
                    s_right_color == Color.BLACK):


    def remove(self, del_value):
        """
        Case I  : removed_node is 'red', replacement is either 'red' or None
        Case II : removed_node is 'red', replacement is 'black'
        Case III: removed_node is 'black', replacement is either 'black' or None
        Case IV : removed_node is 'black', replacement is 'red'
        """
        removed_node, replacement = self.__get_node_and_replacement(del_value,
                                                                    self.root)
        print("replacement:", replacement)
        # couldn't find the del_value in the tree
        if removed_node.get_data() != del_value:
            return

        # Case I (replace red-node with red-node/None)
        if removed_node.get_color() == Color.RED and \
            (replacement is None or replacement.get_color() == Color.RED):
            print("Case I (replace red-node with red-node/None)")
            self.__transplant(removed_node, replacement)
        
        # Case II (replace red-node with black-node)
        elif removed_node.get_color() == Color.RED and \
            replacement.get_color() == Color.BLACK:
            print("Case II (replace red-node with black-node)")
            raise ValueError("This case shouldn't occur!!")
        
        # Case III (replace black-node with black-node)
        elif removed_node.get_color() == Color.BLACK and \
            (replacement is None or replacement.get_color() == Color.BLACK):
            print("Case III (double black-node)")
            parent, transplanted = self.__transplant(removed_node, replacement)
            double_black_node = transplanted
            # handle this double black
            root = self.__handle_double_black(parent, double_black_node)
            self.root = root
        
        # Case IV (replace black-node with red-node/None)
        elif removed_node.get_color() == Color.BLACK and \
            replacement.get_color() == Color.RED:
            print("Case IV (replace black-node with black-node/None)")
            self.__transplant(removed_node, replacement)
def gimme_a_tree():
    vals = [3, 4, 1, 0, 7, 9, 8, 6, 10]
    head = TreeNode(5)
    for v in vals:
        head.insert(v)
    return head
def test_balance():
    tree = TreeNode(5)
    assert tree.balance() == 0
    tree.insert(1)
    assert tree.balance() == 1
    tree.insert(6)
    assert tree.balance() == 0
    tree.insert(3)
    tree.insert(4)
    assert tree.balance() == 2
def test_contains():
    tree = TreeNode(0)
    assert tree.contains(2) is False
    tree.insert(2)
    assert tree.contains(2)
def test_depth():
    tree = TreeNode(5)
    assert tree.depth() == 1
    tree.insert(1)
    assert tree.depth() == 2
    tree.insert(6)
    assert tree.depth() == 2
    tree.insert(3)
    assert tree.depth() == 3
Exemple #16
0
def tree_node():
    from bst import TreeNode
    return TreeNode()
Exemple #17
0
            return left
        elif right:
            return right
        return None


def findLowestAnsestorBST(root, n1, n2):
    if root is None:
        return None
    else:
        if root.data > n1 and root.data > n2:
            findLowestAnsestorBST(root.left, n1, n2)
        elif root.data < n1 and root.data < n2:
            findLowestAnsestor(root.right, n1, n2)
        return root


if __name__ == '__main__':
    root = TreeNode(1)
    root.left = TreeNode(2)
    root.right = TreeNode(3)
    root.left.left = TreeNode(4)
    root.left.right = TreeNode(5)
    root.right.left = TreeNode(6)
    root.right.right = TreeNode(7)

    print "LCA(4, 5) = ", findLowestAnsestor(root, 4, 5)
    print "LCA(4, 6) = ", findLowestAnsestor(root, 4, 6)
    print "LCA(3, 4) = ", findLowestAnsestor(root, 3, 4)
    print "LCA(2, 4) = ", findLowestAnsestor(root, 2, 4)
        raise NotImplementedError("You can't check height of Splay Trees!!")

    def get_depth(self):
        raise NotImplementedError("You can't check depth of Splay Trees!!")







if __name__ == "__main__":
    # test insert
    # example from Data Structures and Algorithm in Python (page: 514)
    stree = SplayTree(8)
    stree.root.set_left(TreeNode(3))
    stree.root.get_left().set_right(TreeNode(4))
    stree.root.get_left().get_right().set_right(TreeNode(6))
    stree.root.get_left().get_right().get_right().set_left(TreeNode(5))
    stree.root.get_left().get_right().get_right().set_right(TreeNode(7))
    stree.root.set_right(TreeNode(10))
    stree.root.get_right().set_right(TreeNode(11))
    stree.root.get_right().get_right().set_right(TreeNode(12))
    stree.root.get_right().get_right().get_right().set_right(TreeNode(16))
    stree.root.get_right().get_right().get_right().get_right().set_left(TreeNode(13))
    stree.root.get_right().get_right().get_right().get_right().set_right(TreeNode(17))
    stree.insert(14)
    stree.find(13)
    print(stree)
    stree.find(8)
    print(stree)