diff --git a/src/balanced_bst.py b/src/balanced_bst.py new file mode 100644 index 0000000..b49b9c6 --- /dev/null +++ b/src/balanced_bst.py @@ -0,0 +1,516 @@ +"""Module for Binary Search Tree.""" + +from queue_ds import Queue +import timeit +import random + + +class Node(object): + """Node class.""" + + def __init__(self, value=None, left=None, right=None): + """Init of the Node class.""" + self.value = value + self.left = left + self.right = right + self.parent = None + + +class BinarySearchTree(object): + """Binary Search Tree.""" + + """insert(self, val): will insert the value val into the BST. If val is already present, it will be ignored.""" + """search(self, val): will return the node containing that value, else None""" + """size(self): will return the integer size of the BST (equal to the total number of values stored in the tree). It will return 0 if the tree is empty.""" + """depth(self): will return an integer representing the total number of levels in the tree. If there is one value, the depth should be 1, if two values it will be 2, if three values it may be 2 or three, depending, etc.""" + """contains(self, val): will return True if val is in the BST, False if not.""" + """balance(self): will return an integer, positive or negative that represents how well balanced the tree is. Trees which are higher on the left than the right should return a positive value, trees which are higher on the right than the left should return a negative value. An ideally-balanced tree should return 0.""" + """in_order(self): will return a generator that will return the values in the tree using in-order traversal, one at a time.""" + """pre_order(self): will return a generator that will return the values in the tree using pre-order traversal, one at a time.""" + """post_order(self): will return a generator that will return the values in the tree using post_order traversal, one at a time.""" + """breadth_first(self): will return a generator that will return the values in the tree using breadth-first traversal, one at a time.""" + + def __init__(self, if_iter=None): + """Init of the Binary Search Tree class.""" + self.root = None + self.counter = 0 + if if_iter: + try: + for value in if_iter: + self.insert(value) + except TypeError: + self.insert(if_iter) + self._in_order = self._in_order_trav() + self._pre_order = self._pre_order_trav() + self._post_order = self._post_order_trav() + self._breadth_first = self._breadth_first_trav() + + def size(self): + """Return size of Binary Search Tree.""" + return self.counter + + def contains(self, val): + """Return True if val is in the BST, False if not.""" + if self.search(val): + return True + return False + + def search(self, val): + """Return the node containing that value, else None.""" + vertex = self.root + while vertex: + if val > vertex.value: + if not vertex.right: + return None + vertex = vertex.right + elif val < vertex.value: + if not vertex.left: + return None + vertex = vertex.left + else: + return vertex + return None + + def depth(self): + """ + Return an integer representing the total number of levels in the tree. + + If there is one value, the depth should be 1, if two values it will be 2, + if three values it may be 2 or three, depending, etc. + """ + return self._calc_depth(self.root) + + def _calc_depth(self, tree): + """Calculate the depth of the binary search tree recursively.""" + if tree is None: + return 0 + else: + return max(self._calc_depth(tree.right), self._calc_depth(tree.left)) + 1 + + def balance(self): + """ + Return an integer, positive or negative that represents how well balanced the tree is. + + Trees which are higher on the left than the right should return a positive value, + trees which are higher on the right than the left should return a negative value. + An ideally-balanced tree should return 0. + """ + if self.root is None: + return 0 + return self._calc_balance(self.root) + + def _calc_balance(self, node): + """Calculate the balance of a subtree at node.""" + return self._calc_depth(node.right) - self._calc_depth(node.left) + + def in_order(self): + """Return the next value from the generator _in_order.""" + return next(self._in_order) + + def _in_order_trav(self): + """Traverse in_order, yielding via generator.""" + vertex = self.root + visited = [] + while (visited or vertex is not None): + + if vertex is not None: + visited.append(vertex) + vertex = vertex.left + else: + vertex = visited.pop() + yield vertex.value + vertex = vertex.right + + def pre_order(self): + """Return the next value from the generator _pre_order.""" + return next(self._pre_order) + + def _pre_order_trav(self): + """Traverse pre_order, yielding via generator.""" + vertex = self.root + visited = [] + while (visited or vertex is not None): + if vertex is not None: + yield vertex.value + visited.append(vertex) + vertex = vertex.left + else: + vertex = visited.pop() + vertex = vertex.right + + def post_order(self): + """Return the next value from the generator _post_order.""" + return next(self._post_order) + + def _post_order_trav(self): + """Traverse pre_order, yielding via generator.""" + vertex = self.root + peek_vertex = None + last_vertex = None + visited = [] + while (visited or vertex is not None): + if vertex is not None: + visited.append(vertex) + vertex = vertex.left + else: + peek_vertex = visited[-1] + if peek_vertex.right and peek_vertex.right is not last_vertex: + vertex = peek_vertex.right + else: + yield peek_vertex.value + last_vertex = visited.pop() + + def breadth_first(self): + """Return the next value from the generator _breadth_first.""" + return next(self._breadth_first) + + def _breadth_first_trav(self): + """Traverse breadth first order, yielding a generator.""" + q = Queue() + q.enqueue(self.root) + while len(q) > 0: + vertex = q.dequeue() + yield vertex.value + if (vertex.left): + q.enqueue(vertex.left) + if (vertex.right): + q.enqueue(vertex.right) + + def insert(self, val): + """Take a value, inserts into Binary Search Tree at correct placement.""" + if self.root is None: + self.root = Node(val) + self.counter += 1 + + else: + vertex = self.root + while True: + if val > vertex.value: + if vertex.right: + vertex = vertex.right + else: + new_node = Node(val) + vertex.right = new_node + new_node.parent = vertex + self.counter += 1 + break + + elif val < vertex.value: + if vertex.left: + vertex = vertex.left + else: + new_node = Node(val) + vertex.left = new_node + new_node.parent = vertex + self.counter += 1 + break + else: + break + self._balance_tree() + + def delete(self, val): + """Remove val from the tree if present, if not present this method is a no-op. Return None in all cases.""" + vertex = self.root + parent_of_del = None + del_node = None + if self.root is None: + return + if self.root.value == val: + left = self.root.left + right = self.root.right + if not right: + self.root = self.root.left + self.root.parent = None + self.counter -= 1 + self._balance_tree() + return + if not right.left: + self.root = right + self.root.left = left + self.root.parent = None + self.counter -= 1 + self._balance_tree() + return + vertex = vertex.right + while True: + if not vertex.left.left: + min_parent = vertex + break + else: + vertex = vertex.left + min_node = min_parent.left + min_parent.left = min_node.right + if min_parent.left: + min_parent.left.parent = min_parent + self.root = min_node + self.root.left = left + self.root.right = right + self.root.parent = None + self.counter -= 1 + self._balance_tree() + else: + while True: + if vertex.right and val == vertex.right.value: + parent_of_del = vertex + del_node = parent_of_del.right + min_parent = self._find_min_parent(parent_of_del, "right") + break + elif vertex.left and val == vertex.left.value: + parent_of_del = vertex + del_node = parent_of_del.left + min_parent = self._find_min_parent(parent_of_del, "left") + break + elif val > vertex.value and vertex.right: + vertex = vertex.right + elif val < vertex.value and vertex.left: + vertex = vertex.left + else: + self._balance_tree() + return + + if parent_of_del.right and val == parent_of_del.right.value: + if not min_parent: + parent_of_del.right = None + self.counter -= 1 + self._balance_tree() + return + if min_parent is del_node: + right = del_node.right + del_node_left = del_node.left + parent_of_del.right = right + if right: + right.parent = parent_of_del + parent_of_del.right.left = del_node_left + if del_node_left: + del_node_left.parent = parent_of_del.right + self.counter -= 1 + self._balance_tree() + return + left = del_node.left + right = del_node.right + min_node = min_parent.left + min_parent.left = min_node.right + if min_parent.left: + min_parent.left.parent = min_parent + del_node = min_node + del_node.right = right + if right: + del_node.right.parent = del_node + del_node.left = left + if left: + del_node.left.parent = del_node + parent_of_del.right = del_node + if del_node: + parent_of_del.right.parent = parent_of_del + self.counter -= 1 + self._balance_tree() + + elif parent_of_del.left and val == parent_of_del.left.value: + if not min_parent: + parent_of_del.left = None + self.counter -= 1 + self._balance_tree() + return + if min_parent is del_node: + left = del_node.right + del_node_left = del_node.left + parent_of_del.left = left + if left: + left.parent = parent_of_del + parent_of_del.left.left = del_node_left + if del_node_left: + del_node_left.parent = parent_of_del.right + self.counter -= 1 + self._balance_tree() + return + left = del_node.left + right = del_node.right + min_node = min_parent.left + min_parent.left = min_node.right + if min_parent.left: + min_parent.left.parent = min_parent + del_node = min_node + del_node.right = right + if right: + del_node.right.parent = del_node + del_node.left = left + if left: + del_node.left.parent = del_node + parent_of_del.left = del_node + if del_node: + parent_of_del.left.parent = parent_of_del + self.counter -= 1 + self._balance_tree() + + def _find_min_parent(self, vertex, side): + """Find the parent of the replacement node, given the parent of the delete node.""" + if side == "right": + if not vertex.right.right and not vertex.right.left: + return + if vertex.right.right and not vertex.right.right.left: + return vertex.right + elif vertex.right.right and vertex.right.right.left: + vertex = vertex.right.right + while True: + if not vertex.left.left: + return vertex + else: + vertex = vertex.left + else: + if not vertex.left.right and not vertex.left.left: + return + if vertex.left.right and not vertex.left.right.left: + return vertex.left + elif vertex.left.right and vertex.left.right.left: + vertex = vertex.left.right + while True: + if not vertex.left.left: + return vertex + else: + vertex = vertex.left + return + + def _balance_tree(self): + for node in self._post_order_node(): + if self._calc_balance(node) > 1: + if self._calc_balance(node.right) < 0: + self._right_left_rotation(node) + else: + self._left_rotation(node) + elif self._calc_balance(node) < -1: + if self._calc_balance(node.left) > 0: + self._left_right_rotation(node) + else: + self._right_rotation(node) + + def _left_rotation(self, node): + a = node + a_parent = a.parent + b = a.right + d = b.left + if a is self.root: + self.root = b + self.root.parent = None + self.root.left = a + a.parent = self.root + a.right = d + if d: + d.parent = a + return + a_parent.right = b + b.parent = a_parent + b.left = a + a.parent = b + a.right = d + if d: + d.parent = a + + def _right_rotation(self, node): + a = node + a_parent = a.parent + b = a.left + d = b.right + if a is self.root: + self.root = b + self.root.parent = None + self.root.right = a + a.parent = self.root + a.left = d + if d: + d.parent = a + return + a_parent.left = b + b.parent = a_parent + b.right = a + a.parent = b + a.left = d + if d: + d.parent = a + + def _left_right_rotation(self, node): + """Left right rotation on a BST.""" + vertex = node + left_head = node.left + right_sub = node.left.right + if node.left.right.left: + switcher = node.left.right.left + switcher.parent = left_head + left_head.right = switcher + vertex.left = None + elif node.left.right.right: + switcher = node.left.right.right + switcher.parent = vertex + vertex.left = switcher + left_head.right = None + else: + vertex.left = None + left_head.right = None + if vertex.parent: + right_sub.parent = vertex.parent + if vertex.parent.value > vertex.value: + vertex.parent.left = right_sub + else: + vertex.parent.right = right_sub + else: + self.root = right_sub + right_sub.parent = None + left_head.parent = right_sub + right_sub.right = vertex + right_sub.left = left_head + vertex.parent = right_sub + + def _right_left_rotation(self, node): + """Right left rotation on a BST.""" + vertex = node + right_head = node.right + left_sub = node.right.left + if node.right.left.right: + switcher = node.right.left.right + switcher.parent = right_head + right_head.left = switcher + vertex.right = None + elif node.right.left.left: + switcher = node.right.left.left + switcher.parent = vertex + vertex.right = switcher + right_head.left = None + else: + vertex.right = None + right_head.left = None + if vertex.parent: + left_sub.parent = vertex.parent + if vertex.parent.value > vertex.value: + vertex.parent.left = left_sub + else: + vertex.parent.right = left_sub + else: + self.root = left_sub + left_sub.parent = None + right_head.parent = left_sub + left_sub.right = right_head + left_sub.left = vertex + vertex.parent = left_sub + + def _post_order_node(self): + vertex = self.root + peek_vertex = None + last_vertex = None + visited = [] + while (visited or vertex is not None): + if vertex is not None: + visited.append(vertex) + vertex = vertex.left + else: + peek_vertex = visited[-1] + if peek_vertex.right and peek_vertex.right is not last_vertex: + vertex = peek_vertex.right + else: + yield peek_vertex + last_vertex = visited.pop() + +# if __name__ == "__main__": + +# res1 = timeit.repeat(stmt="depth(g)", setup="from graph import g, depth", number=10, repeat=3) +# res2 = timeit.repeat(stmt="breadth(g)", setup="from graph import g, breadth", number=10, repeat=3) +# print("Depth First: ", res1) +# print("Breadth First: ", res2) diff --git a/src/bst.py b/src/bst.py new file mode 100644 index 0000000..e8bba13 --- /dev/null +++ b/src/bst.py @@ -0,0 +1,330 @@ +"""Module for Binary Search Tree.""" + +from queue_ds import Queue +import timeit +import random + + +class Node(object): + """Node class.""" + + def __init__(self, value=None, left=None, right=None): + """Init of the Node class.""" + self.value = value + self.left = left + self.right = right + + +class BinarySearchTree(object): + """Binary Search Tree.""" + + """insert(self, val): will insert the value val into the BST. If val is already present, it will be ignored.""" + """search(self, val): will return the node containing that value, else None""" + """size(self): will return the integer size of the BST (equal to the total number of values stored in the tree). It will return 0 if the tree is empty.""" + """depth(self): will return an integer representing the total number of levels in the tree. If there is one value, the depth should be 1, if two values it will be 2, if three values it may be 2 or three, depending, etc.""" + """contains(self, val): will return True if val is in the BST, False if not.""" + """balance(self): will return an integer, positive or negative that represents how well balanced the tree is. Trees which are higher on the left than the right should return a positive value, trees which are higher on the right than the left should return a negative value. An ideally-balanced tree should return 0.""" + """in_order(self): will return a generator that will return the values in the tree using in-order traversal, one at a time.""" + """pre_order(self): will return a generator that will return the values in the tree using pre-order traversal, one at a time.""" + """post_order(self): will return a generator that will return the values in the tree using post_order traversal, one at a time.""" + """breadth_first(self): will return a generator that will return the values in the tree using breadth-first traversal, one at a time.""" + + def __init__(self, if_iter=None): + """Init of the Binary Search Tree class.""" + self.root = None + self.counter = 0 + if if_iter: + try: + for value in if_iter: + self.insert(value) + except TypeError: + self.insert(if_iter) + self._in_order = self._in_order_trav() + self._pre_order = self._pre_order_trav() + self._post_order = self._post_order_trav() + self._breadth_first = self._breadth_first_trav() + + def insert(self, val): + """Take a value, inserts into Binary Search Tree at correct placement.""" + if self.root is None: + self.root = Node(val) + self.counter += 1 + + else: + vertex = self.root + while True: + if val > vertex.value: + if vertex.right: + vertex = vertex.right + else: + vertex.right = Node(val) + self.counter += 1 + break + + elif val < vertex.value: + if vertex.left: + vertex = vertex.left + else: + vertex.left = Node(val) + self.counter += 1 + break + else: + break + + def size(self): + """Return size of Binary Search Tree.""" + return self.counter + + def contains(self, val): + """Return True if val is in the BST, False if not.""" + if self.search(val): + return True + return False + + def search(self, val): + """Return the node containing that value, else None.""" + vertex = self.root + while vertex: + if val > vertex.value: + if not vertex.right: + return None + vertex = vertex.right + elif val < vertex.value: + if not vertex.left: + return None + vertex = vertex.left + else: + return vertex + return None + + def depth(self): + """ + Return an integer representing the total number of levels in the tree. + + If there is one value, the depth should be 1, if two values it will be 2, + if three values it may be 2 or three, depending, etc. + """ + return self._calc_depth(self.root) + + def _calc_depth(self, tree): + """Calculate the depth of the binary search tree recursively.""" + if tree is None: + return 0 + else: + return max(self._calc_depth(tree.right), self._calc_depth(tree.left)) + 1 + + def balance(self): + """ + Return an integer, positive or negative that represents how well balanced the tree is. + + Trees which are higher on the left than the right should return a positive value, + trees which are higher on the right than the left should return a negative value. + An ideally-balanced tree should return 0. + """ + if self.root is None: + return 0 + return self._calc_depth(self.root.right) - self._calc_depth(self.root.left) + + def in_order(self): + """Return the next value from the generator _in_order.""" + return next(self._in_order) + + def _in_order_trav(self): + """Traverse in_order, yielding via generator.""" + vertex = self.root + visited = [] + while (visited or vertex is not None): + + if vertex is not None: + visited.append(vertex) + vertex = vertex.left + else: + vertex = visited.pop() + yield vertex.value + vertex = vertex.right + + def pre_order(self): + """Return the next value from the generator _pre_order.""" + return next(self._pre_order) + + def _pre_order_trav(self): + """Traverse pre_order, yielding via generator.""" + vertex = self.root + visited = [] + while (visited or vertex is not None): + if vertex is not None: + yield vertex.value + visited.append(vertex) + vertex = vertex.left + else: + vertex = visited.pop() + vertex = vertex.right + + def post_order(self): + """Return the next value from the generator _post_order.""" + return next(self._post_order) + + def _post_order_trav(self): + """Traverse pre_order, yielding via generator.""" + vertex = self.root + peek_vertex = None + last_vertex = None + visited = [] + while (visited or vertex is not None): + if vertex is not None: + visited.append(vertex) + vertex = vertex.left + else: + peek_vertex = visited[-1] + if peek_vertex.right and peek_vertex.right is not last_vertex: + vertex = peek_vertex.right + else: + yield peek_vertex.value + last_vertex = visited.pop() + + def breadth_first(self): + """Return the next value from the generator _breadth_first.""" + return next(self._breadth_first) + + def _breadth_first_trav(self): + """Traverse breadth first order, yielding a generator.""" + q = Queue() + q.enqueue(self.root) + while len(q) > 0: + vertex = q.dequeue() + yield vertex.value + if (vertex.left): + q.enqueue(vertex.left) + if (vertex.right): + q.enqueue(vertex.right) + + def delete(self, val): + """Remove val from the tree if present, if not present this method is a no-op. Return None in all cases.""" + vertex = self.root + parent_of_del = None + del_node = None + if self.root is None: + return + if self.root.value == val: + left = self.root.left + right = self.root.right + if not right: + self.root = self.root.left + self.counter -= 1 + return + if not right.left: + self.root = right + self.root.left = left + self.counter -= 1 + return + vertex = vertex.right + while True: + if not vertex.left.left: + min_parent = vertex + break + else: + vertex = vertex.left + min_node = min_parent.left + min_parent.left = min_node.right + self.root = min_node + self.root.left = left + self.root.right = right + self.counter -= 1 + else: + while True: + if vertex.right and val == vertex.right.value: + parent_of_del = vertex + del_node = parent_of_del.right + min_parent = self._find_min_parent(parent_of_del, "right") + break + elif vertex.left and val == vertex.left.value: + parent_of_del = vertex + del_node = parent_of_del.left + min_parent = self._find_min_parent(parent_of_del, "left") + break + elif val > vertex.value and vertex.right: + vertex = vertex.right + elif val < vertex.value and vertex.left: + vertex = vertex.left + else: + return + + if parent_of_del.right and val == parent_of_del.right.value: + if not min_parent: + parent_of_del.right = None + self.counter -= 1 + return + if min_parent is del_node: + right = del_node.right + del_node_left = del_node.left + parent_of_del.right = right + parent_of_del.right.left = del_node_left + self.counter -= 1 + return + left = del_node.left + right = del_node.right + min_node = min_parent.left + min_parent.left = min_node.right + del_node = min_node + del_node.right = right + del_node.left = left + parent_of_del.right = del_node + self.counter -= 1 + + elif parent_of_del.left and val == parent_of_del.left.value: + if not min_parent: + parent_of_del.left = None + self.counter -= 1 + return + if min_parent is del_node: + left = del_node.right + del_node_left = del_node.left + parent_of_del.left = left + parent_of_del.left.left = del_node_left + self.counter -= 1 + return + left = del_node.left + right = del_node.right + min_node = min_parent.left + min_parent.left = min_node.right + del_node = min_node + del_node.right = right + del_node.left = left + parent_of_del.left = del_node + self.counter -= 1 + + def _find_min_parent(self, vertex, side): + """Find the parent of the replacement node, given the parent of the delete node.""" + if side == "right": + if not vertex.right.right and not vertex.right.left: + return + if vertex.right.right and not vertex.right.right.left: + return vertex.right + elif vertex.right.right and vertex.right.right.left: + vertex = vertex.right.right + while True: + if not vertex.left.left: + return vertex + else: + vertex = vertex.left + else: + if not vertex.left.right and not vertex.left.left: + return + if vertex.left.right and not vertex.left.right.left: + return vertex.left + elif vertex.left.right and vertex.left.right.left: + vertex = vertex.left.right + while True: + if not vertex.left.left: + return vertex + else: + vertex = vertex.left + return + + +# if __name__ == "__main__": + +# res1 = timeit.repeat(stmt="depth(g)", setup="from graph import g, depth", number=10, repeat=3) +# res2 = timeit.repeat(stmt="breadth(g)", setup="from graph import g, breadth", number=10, repeat=3) +# print("Depth First: ", res1) +# print("Breadth First: ", res2) diff --git a/src/hash_table.py b/src/hash_table.py new file mode 100644 index 0000000..3ae4f3c --- /dev/null +++ b/src/hash_table.py @@ -0,0 +1,25 @@ +# HASH TABLE (HT) +# +# CodeFellows 401d5 +# Submission Date: +# +# Authors: Colin Lamont +# Ben Shields +# +# URL: + + +""" +The Mailroom module allows the user to +track donations and format emails for donors. +The user can write tailored thank you emails +given donor names and donation amounts. +The user can create a report that is +a list of donor names and their corresponding donation +histories, arranged by in order of the total amount +donated. +The user can add a donor name to this list. +The user can quit the program from Main Menu, and +may return to Main Menu at any time. +""" + diff --git a/src/test_balanced_bst.py b/src/test_balanced_bst.py new file mode 100644 index 0000000..5a77c71 --- /dev/null +++ b/src/test_balanced_bst.py @@ -0,0 +1,838 @@ +"""Test Module for Balanced Binary Search Tree.""" +from balanced_bst import BinarySearchTree +import pytest + +BST_ROT_2_R_1 = [3, 2] +BST_ROT_2_L_3 = [1, 2] +BST_ROT_LR_GC_7 = [10, 12, 5, 8, 2] +BST_ROT_RL = [10, 5, 15, 13, 20] + + +@pytest.fixture +def filled_bst_rot_2_r_1(): + """Fixture for a 2 node tree for a right rotation with insertion of 1.""" + new_tree = BinarySearchTree(BST_ROT_2_R_1) + return new_tree + + +@pytest.fixture +def filled_bst_rot_2_l_3(): + """Fixture for a 2 node tree for a left rotation with insertion of 3.""" + new_tree = BinarySearchTree(BST_ROT_2_L_3) + return new_tree + + +@pytest.fixture +def filled_bst_rot_lr_gc_7(): + """Fixture for a binary search tree for a left-right rotation with insertion of 7 to tree 10, 12, 5, 8, 2.""" + new_tree = BinarySearchTree(BST_ROT_LR_GC_7) + return new_tree + + +@pytest.fixture +def filled_bst_rot_rl(): + """Fixture for a binary search tree for a right-left rotation.""" + new_tree = BinarySearchTree(BST_ROT_RL) + return new_tree + + +def test_simple_3_node_right_rotation(filled_bst_rot_2_r_1): + """Balance bst via right rotation, when adding 1 to tree of 3, 2.""" + a = filled_bst_rot_2_r_1 + a.insert(1) + assert a.root.value == 2 + assert a.root.right.value == 3 + assert a.root.left.value == 1 + + +def test_simple_3_node_left_rotation(filled_bst_rot_2_l_3): + """Balance bst via left rotation, when adding 3 to tree of 1, 2.""" + a = filled_bst_rot_2_l_3 + a.insert(3) + assert a.root.value == 2 + assert a.root.right.value == 3 + assert a.root.left.value == 1 + + +def test_left_right_rotation(filled_bst_rot_lr_gc_7): + """Balance bst via left-right rotation, when adding 7 to tree of 10, 12, 5, 8, 2.""" + a = filled_bst_rot_lr_gc_7 + a.insert(7) + assert a.root.value == 8 + assert a.root.right.value == 10 + assert a.root.left.value == 5 + assert a.root.left.right.value == 7 + assert a.root.left.left.value == 2 + assert a.root.right.right.value == 12 + + +def test_bst_empty_tree(): + """Test balancing empty tree.""" + a = BinarySearchTree() + assert a.root is None + + +def test_bst_1_value(): + """Test balancing tree with one value.""" + a = BinarySearchTree() + a.insert(1) + assert a.root.value == 1 + assert a.root.right is None + assert a.root.left is None + + +def test_bst_2_values(): + """Test balancing tree with two values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + assert a.root.value == 1 + assert a.root.right.value == 2 + assert a.root.left is None + + +def test_bst_3_values(): + """Test balancing tree with three values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + assert a.root.value == 2 + assert a.root.right.value == 3 + assert a.root.left.value == 1 + + +def test_bst_4_values(): + """Test balancing tree with four values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + assert a.root.value == 2 + assert a.root.right.value == 3 + assert a.root.left.value == 1 + assert a.root.right.right.value == 4 + + +def test_bst_5_values(): + """Test balancing tree with five values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + assert a.root.value == 2 + assert a.root.right.value == 4 + assert a.root.left.value == 1 + assert a.root.right.right.value == 5 + assert a.root.right.left.value == 3 + + +def test_bst_6_values(): + """Test balancing tree with six values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + assert a.root.value == 4 + assert a.root.right.value == 5 + assert a.root.left.value == 2 + assert a.root.right.right.value == 6 + assert a.root.left.left.value == 1 + assert a.root.left.right.value == 3 + + +def test_bst_7_values(): + """Test balancing tree with seven values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + assert a.root.value == 4 + assert a.root.right.value == 6 + assert a.root.left.value == 2 + assert a.root.right.right.value == 7 + assert a.root.left.left.value == 1 + assert a.root.left.right.value == 3 + assert a.root.right.left.value == 5 + + +def test_bst_8_values(): + """Test balancing tree with eight values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + a.insert(8) + assert a.root.value == 4 + assert a.root.right.value == 6 + assert a.root.left.value == 2 + assert a.root.right.right.value == 7 + assert a.root.left.left.value == 1 + assert a.root.left.right.value == 3 + assert a.root.right.left.value == 5 + assert a.root.right.right.right.value == 8 + + +def test_bst_9_values(): + """Test balancing tree with nine values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + a.insert(8) + a.insert(9) + assert a.root.value == 4 + assert a.root.right.value == 6 + assert a.root.left.value == 2 + assert a.root.right.right.value == 8 + assert a.root.left.left.value == 1 + assert a.root.left.right.value == 3 + assert a.root.right.left.value == 5 + assert a.root.right.right.right.value == 9 + assert a.root.right.right.left.value == 7 + + +def test_bst_10_values(): + """Test balancing tree with ten values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + a.insert(8) + a.insert(9) + a.insert(10) + assert a.root.value == 4 + assert a.root.right.value == 8 + assert a.root.left.value == 2 + assert a.root.right.right.value == 9 + assert a.root.left.left.value == 1 + assert a.root.left.right.value == 3 + assert a.root.right.right.right.value == 10 + assert a.root.right.left.value == 6 + assert a.root.right.left.right.value == 7 + assert a.root.right.left.left.value == 5 + + +def test_bst_11_values(): + """Test balancing tree with eleven values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + a.insert(8) + a.insert(9) + a.insert(10) + a.insert(11) + assert a.root.value == 4 + assert a.root.right.value == 8 + assert a.root.left.value == 2 + assert a.root.right.right.value == 10 + assert a.root.left.left.value == 1 + assert a.root.left.right.value == 3 + assert a.root.right.right.right.value == 11 + assert a.root.right.right.left.value == 9 + assert a.root.right.left.value == 6 + assert a.root.right.left.right.value == 7 + assert a.root.right.left.left.value == 5 + + +def test_bst_12_values(): + """Test balancing tree with twelve values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + a.insert(8) + a.insert(9) + a.insert(10) + a.insert(11) + a.insert(12) + assert a.root.value == 8 + assert a.root.right.value == 10 + assert a.root.right.right.value == 11 + assert a.root.right.left.value == 9 + assert a.root.right.right.right.value == 12 + assert a.root.left.value == 4 + assert a.root.left.left.value == 2 + assert a.root.left.left.left.value == 1 + assert a.root.left.left.right.value == 3 + assert a.root.left.right.value == 6 + assert a.root.left.right.left.value == 5 + assert a.root.left.right.right.value == 7 + + +def test_bst_13_values(): + """Test balancing tree with thirteen values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + a.insert(8) + a.insert(9) + a.insert(10) + a.insert(11) + a.insert(12) + a.insert(13) + assert a.root.value == 8 + assert a.root.right.value == 10 + assert a.root.right.right.value == 12 + assert a.root.right.left.value == 9 + assert a.root.right.right.right.value == 13 + assert a.root.right.right.left.value == 11 + assert a.root.left.value == 4 + assert a.root.left.left.value == 2 + assert a.root.left.left.left.value == 1 + assert a.root.left.left.right.value == 3 + assert a.root.left.right.value == 6 + assert a.root.left.right.left.value == 5 + assert a.root.left.right.right.value == 7 + + +def test_bst_14_values(): + """Test balancing tree with fourteen values.""" + a = BinarySearchTree() + a.insert(1) + a.insert(2) + a.insert(3) + a.insert(4) + a.insert(5) + a.insert(6) + a.insert(7) + a.insert(8) + a.insert(9) + a.insert(10) + a.insert(11) + a.insert(12) + a.insert(13) + a.insert(14) + assert a.root.value == 8 + assert a.root.right.value == 12 + assert a.root.right.right.value == 13 + assert a.root.right.left.value == 10 + assert a.root.right.right.right.value == 14 + assert a.root.right.left.left.value == 9 + assert a.root.right.left.right.value == 11 + assert a.root.left.value == 4 + assert a.root.left.left.value == 2 + assert a.root.left.left.left.value == 1 + assert a.root.left.left.right.value == 3 + assert a.root.left.right.value == 6 + assert a.root.left.right.left.value == 5 + assert a.root.left.right.right.value == 7 + + +def test_bst_1_value_starting_at_14_down(): + """Test balancing tree with one value.""" + a = BinarySearchTree() + a.insert(14) + assert a.root.value == 14 + assert a.root.right is None + assert a.root.left is None + + +def test_bst_2_values_starting_at_14_down(): + """Test balancing tree with two values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + assert a.root.value == 14 + assert a.root.right is None + assert a.root.left.value == 13 + + +def test_bst_3_values_starting_at_14_down(): + """Test balancing tree with three values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + assert a.root.value == 13 + assert a.root.right.value == 14 + assert a.root.left.value == 12 + + +def test_bst_4_values_starting_at_14_down(): + """Test balancing tree with four values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + assert a.root.value == 13 + assert a.root.right.value == 14 + assert a.root.left.value == 12 + assert a.root.left.left.value == 11 + + +def test_bst_5_values_starting_at_14_down(): + """Test balancing tree with five values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + assert a.root.value == 13 + assert a.root.right.value == 14 + assert a.root.left.value == 11 + assert a.root.left.right.value == 12 + assert a.root.left.left.value == 10 + + +def test_bst_6_values_starting_at_14_down(): + """Test balancing tree with six values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + assert a.root.value == 11 + assert a.root.right.value == 13 + assert a.root.left.value == 10 + assert a.root.right.right.value == 14 + assert a.root.right.left.value == 12 + assert a.root.left.left.value == 9 + + +def test_bst_7_values_starting_at_14_down(): + """Test balancing tree with seven values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + assert a.root.value == 11 + assert a.root.right.value == 13 + assert a.root.left.value == 9 + assert a.root.right.right.value == 14 + assert a.root.left.left.value == 8 + assert a.root.left.right.value == 10 + assert a.root.right.left.value == 12 + + +def test_bst_8_values_starting_at_14_down(): + """Test balancing tree with eight values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + a.insert(7) + assert a.root.value == 11 + assert a.root.right.value == 13 + assert a.root.left.value == 9 + assert a.root.right.right.value == 14 + assert a.root.left.left.value == 8 + assert a.root.left.right.value == 10 + assert a.root.right.left.value == 12 + assert a.root.left.left.left.value == 7 + + +def test_bst_9_values_starting_at_14_down(): + """Test balancing tree with nine values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + a.insert(7) + a.insert(6) + assert a.root.value == 11 + assert a.root.right.value == 13 + assert a.root.left.value == 9 + assert a.root.right.right.value == 14 + assert a.root.left.left.value == 7 + assert a.root.left.right.value == 10 + assert a.root.right.left.value == 12 + assert a.root.left.left.left.value == 6 + assert a.root.left.left.right.value == 8 + + +def test_bst_10_values_starting_at_14_down(): + """Test balancing tree with ten values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + a.insert(7) + a.insert(6) + a.insert(5) + assert a.root.value == 11 + assert a.root.right.value == 13 + assert a.root.right.right.value == 14 + assert a.root.right.left.value == 12 + assert a.root.left.value == 7 + assert a.root.left.left.value == 6 + assert a.root.left.right.value == 9 + assert a.root.left.left.left.value == 5 + assert a.root.left.right.right.value == 10 + assert a.root.left.right.left.value == 8 + + +def test_bst_11_values_starting_at_14_down(): + """Test balancing tree with eleven values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + a.insert(7) + a.insert(6) + a.insert(5) + a.insert(4) + assert a.root.value == 11 + assert a.root.right.value == 13 + assert a.root.right.right.value == 14 + assert a.root.right.left.value == 12 + assert a.root.left.value == 7 + assert a.root.left.left.value == 5 + assert a.root.left.right.value == 9 + assert a.root.left.left.left.value == 4 + assert a.root.left.right.right.value == 10 + assert a.root.left.right.left.value == 8 + assert a.root.left.left.right.value == 6 + + +def test_bst_12_values_starting_at_14_down(): + """Test balancing tree with twelve values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + a.insert(7) + a.insert(6) + a.insert(5) + a.insert(4) + a.insert(3) + assert a.root.value == 7 + assert a.root.right.value == 11 + assert a.root.right.right.value == 13 + assert a.root.right.left.value == 9 + assert a.root.right.left.left.value == 8 + assert a.root.right.left.right.value == 10 + assert a.root.right.right.left.value == 12 + assert a.root.right.right.right.value == 14 + assert a.root.left.value == 5 + assert a.root.left.left.value == 4 + assert a.root.left.right.value == 6 + assert a.root.left.left.left.value == 3 + + +def test_bst_13_values_starting_at_14_down(): + """Test balancing tree with thirteen values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + a.insert(7) + a.insert(6) + a.insert(5) + a.insert(4) + a.insert(3) + a.insert(2) + assert a.root.value == 7 + assert a.root.right.value == 11 + assert a.root.right.right.value == 13 + assert a.root.right.left.value == 9 + assert a.root.right.left.left.value == 8 + assert a.root.right.left.right.value == 10 + assert a.root.right.right.left.value == 12 + assert a.root.right.right.right.value == 14 + assert a.root.left.value == 5 + assert a.root.left.left.value == 3 + assert a.root.left.right.value == 6 + assert a.root.left.left.left.value == 2 + assert a.root.left.left.right.value == 4 + + +def test_bst_14_values_starting_at_14_down(): + """Test balancing tree with fourteen values.""" + a = BinarySearchTree() + a.insert(14) + a.insert(13) + a.insert(12) + a.insert(11) + a.insert(10) + a.insert(9) + a.insert(8) + a.insert(7) + a.insert(6) + a.insert(5) + a.insert(4) + a.insert(3) + a.insert(2) + a.insert(1) + assert a.root.value == 7 + assert a.root.right.value == 11 + assert a.root.right.right.value == 13 + assert a.root.right.left.value == 9 + assert a.root.right.left.left.value == 8 + assert a.root.right.left.right.value == 10 + assert a.root.right.right.left.value == 12 + assert a.root.right.right.right.value == 14 + assert a.root.left.value == 3 + assert a.root.left.left.value == 2 + assert a.root.left.right.value == 5 + assert a.root.left.left.left.value == 1 + assert a.root.left.right.right.value == 6 + assert a.root.left.right.left.value == 4 + + +def test_bst_left_right_basic(filled_bst_rot_2_r_1): + """Test left right rotation.""" + a = filled_bst_rot_2_r_1 + a.insert(1) + assert a.root.value == 2 + assert a.root.parent is None + assert a.root.left.value == 1 + assert a.root.right.value == 3 + + +def test_bst_right_left_basic(filled_bst_rot_2_l_3): + """Test right left rotation.""" + a = filled_bst_rot_2_l_3 + a.insert(3) + assert a.root.value == 2 + assert a.root.parent is None + assert a.root.left.value == 1 + assert a.root.right.value == 3 + + +def test_bst_left_right_root_left_right_add_left(filled_bst_rot_lr_gc_7): + """Test left right rotation.""" + a = filled_bst_rot_lr_gc_7 + a.insert(7) + assert a.root.value == 8 + assert a.root.parent is None + assert a.root.left.value == 5 + assert a.root.left.left.value == 2 + assert a.root.left.right.value == 7 + assert a.root.right.value == 10 + assert a.root.right.left is None + assert a.root.right.right.value == 12 + + +def test_bst_left_right_root_left_right_add_right(filled_bst_rot_lr_gc_7): + """Test left right rotation.""" + a = filled_bst_rot_lr_gc_7 + a.insert(9) + assert a.root.value == 8 + assert a.root.parent is None + assert a.root.left.value == 5 + assert a.root.left.left.value == 2 + assert a.root.left.right is None + assert a.root.right.value == 10 + assert a.root.right.left.value == 9 + assert a.root.right.right.value == 12 + + +def test_right_left_root_right_left_add_left(filled_bst_rot_rl): + """Test right left rotation.""" + a = filled_bst_rot_rl + a.insert(12) + assert a.root.value == 13 + assert a.root.parent is None + assert a.root.left.value == 10 + assert a.root.left.left.value == 5 + assert a.root.left.right.value == 12 + assert a.root.right.value == 15 + assert a.root.right.left is None + assert a.root.right.right.value == 20 + + +def test_right_left_root_right_left_add_right(filled_bst_rot_rl): + """Test right left rotation.""" + a = filled_bst_rot_rl + a.insert(14) + assert a.root.value == 13 + assert a.root.parent is None + assert a.root.left.value == 10 + assert a.root.left.left.value == 5 + assert a.root.left.right is None + assert a.root.right.value == 15 + assert a.root.right.left.value == 14 + assert a.root.right.right.value == 20 + + +def test_bst_double_rotation_one(): + """Test double rotation one.""" + a = BinarySearchTree([10, 5, 15, 13, 20]) + a.insert(12) + assert a.root.value == 13 + assert a.root.right.value == 15 + assert a.root.left.value == 10 + assert a.root.right.right.value == 20 + assert a.root.left.left.value == 5 + assert a.root.left.right.value == 12 + + +def test_bst_double_rotation_two(): + """Test double rotation one.""" + a = BinarySearchTree([15, 10, 20, 5, 13]) + a.insert(14) + assert a.root.value == 13 + assert a.root.right.value == 15 + assert a.root.left.value == 10 + assert a.root.right.right.value == 20 + assert a.root.right.left.value == 14 + assert a.root.left.left.value == 5 + + +def test_right_left_rotation_on_delete(): + """Test right-left rotation on delete of 7 node tree.""" + a = BinarySearchTree([10, 5, 15, 2, 12, 20, 14]) + a.delete(2) + assert a.root.value == 12 + assert a.root.right.value == 15 + assert a.root.right.right.value == 20 + assert a.root.right.left.value == 14 + assert a.root.left.value == 10 + assert a.root.left.left.value == 5 + assert not a.root.left.right + assert a.root.right.right.parent.value == 15 + assert a.root.right.left.parent.value == 15 + assert a.root.left.left.parent.value == 10 + assert a.root.left.parent.value == 12 + assert a.root.right.parent.value == 12 + assert not a.root.parent + + +def test_right_left_rotation_other_leg_on_delete(): + """Test right-left rotation on delete of a different 7 node tree.""" + a = BinarySearchTree([10, 5, 15, 2, 12, 20, 11]) + a.delete(2) + assert a.root.value == 12 + assert a.root.right.value == 15 + assert a.root.right.right.value == 20 + assert a.root.left.right.value == 11 + assert a.root.left.value == 10 + assert a.root.left.left.value == 5 + assert not a.root.right.left + assert a.root.right.right.parent.value == 15 + assert a.root.left.right.parent.value == 10 + assert a.root.left.left.parent.value == 10 + assert a.root.left.parent.value == 12 + assert a.root.right.parent.value == 12 + assert not a.root.parent + + +def test_right_left_rotation_simple_on_delete(): + """Test right-left rotation on a simple 4 node tree.""" + a = BinarySearchTree([10, 12, 9, 11]) + a.delete(9) + assert a.root.value == 11 + assert a.root.right.value == 12 + assert a.root.left.value == 10 + assert a.root.right.parent.value == 11 + assert a.root.left.parent.value == 11 + assert not a.root.parent + assert not a.root.right.right + assert not a.root.right.left + + +def test_left_right_rotation_on_delet(): + """Test left-right rotation on delete of 7 node tree.""" + a = BinarySearchTree([20, 10, 25, 5, 15, 27, 12]) + a.delete(27) + assert a.root.value == 15 + assert a.root.right.value == 20 + assert a.root.left.value == 10 + assert a.root.right.right.value == 25 + assert a.root.left.right.value == 12 + assert a.root.left.left.value == 5 + assert a.root.left.right.parent.value == 10 + assert a.root.left.left.parent.value == 10 + assert a.root.right.right.parent.value == 20 + assert not a.root.parent + assert not a.root.right.left + + +def test_left_right_rotation_other_leg_on_deletion(): + """Test left-right rotation on delete of a different 7 node tree.""" + a = BinarySearchTree([20, 10, 25, 5, 15, 27, 17]) + a.delete(27) + assert a.root.value == 15 + assert a.root.right.value == 20 + assert a.root.left.value == 10 + assert a.root.right.right.value == 25 + assert a.root.right.left.value == 17 + assert a.root.left.left.value == 5 + assert a.root.right.left.parent.value == 20 + assert a.root.left.left.parent.value == 10 + assert a.root.right.right.parent.value == 20 + assert not a.root.parent + assert not a.root.left.right + + +def test_left_right_rotation_simple_on_deletion(): + """Test left-right rotation on a simple 4 node tree.""" + a = BinarySearchTree([5, 3, 6, 4]) + a.delete(6) + assert a.root.value == 4 + assert a.root.right.value == 5 + assert a.root.left.value == 3 + assert not a.root.parent + assert not a.root.right.right + assert not a.root.right.left + assert a.root.right.parent.value == 4 + assert a.root.left.parent.value == 4 diff --git a/src/test_bst.py b/src/test_bst.py new file mode 100644 index 0000000..6a39301 --- /dev/null +++ b/src/test_bst.py @@ -0,0 +1,504 @@ +"""Test Module for Binary Search Tree.""" +from bst import BinarySearchTree +import pytest + +BST_SIMPLE = [8, 10, 3, 14, 13, 1, 6, 7, 4] +BST_STRAIGHT_LINE = [1, 2, 3, 4, 5, 6, 7] +BST_BIG = [ + 30, 50, 45, 60, 15, 25, 10, 47, 42, + 40, 27, 55, 44, 46, 49, 7, 12, 65, 70, 57, + 63, 52, 23, 4, 9, 11, 13, 21, 24, 26, 28 +] + + +@pytest.fixture +def big_bst(): + """Fixture to fill big bst.""" + from bst import BinarySearchTree + new_tree = BinarySearchTree(BST_BIG) + return new_tree + + +@pytest.fixture +def straight_bst(): + """Fixture to fill bst tree with a straight line of nodes down right side.""" + from bst import BinarySearchTree + new_tree = BinarySearchTree(BST_STRAIGHT_LINE) + return new_tree + + +@pytest.fixture +def filled_bst(): + """Fixture to fill the bst tree with nodes.""" + from bst import BinarySearchTree + new_tree = BinarySearchTree(BST_SIMPLE) + return new_tree + + +def test_insert_5_is_root(): + """Test the insert function.""" + a = BinarySearchTree() + a.insert(5) + assert a.root + + +def test_insert_5_where_root_equals_5(): + """Test the insert funciton.""" + a = BinarySearchTree() + a.insert(5) + assert a.root.value == 5 + + +def test_insert_5_and_10_and_confirm_right(): + """Test the insert function.""" + a = BinarySearchTree() + a.insert(5) + a.insert(10) + assert a.root.right.value == 10 + + +def test_insert_many_numbers(): + """Test the insert function.""" + a = BinarySearchTree() + a.insert(8) + a.insert(10) + a.insert(3) + a.insert(14) + a.insert(13) + a.insert(1) + a.insert(6) + a.insert(7) + a.insert(4) + assert a.root.right.right.left.value == 13 + assert a.root.left.value == 3 + assert a.root.right.right.value == 14 + assert a.root.value == 8 + assert a.root.left.right.left.value == 4 + + +def test_size_returns_size_of_binary_search_tree(): + """Test that the size method returns size of the bst.""" + a = BinarySearchTree() + a.insert(8) + a.insert(10) + a.insert(3) + a.insert(14) + a.insert(13) + a.insert(1) + a.insert(6) + a.insert(7) + a.insert(4) + assert a.size() == 9 + + +def test_binary_search_tree_contains_value(): + """Test that the contains method returns True if value in binary search tree.""" + a = BinarySearchTree() + a.insert(8) + a.insert(10) + a.insert(3) + a.insert(14) + a.insert(13) + a.insert(1) + a.insert(6) + a.insert(7) + a.insert(4) + assert a.contains(4) + + +def test_binary_search_tree_does_not_contain_value(): + """Test that the contains method returns True if value in binary search tree.""" + a = BinarySearchTree() + a.insert(8) + a.insert(10) + a.insert(3) + a.insert(14) + a.insert(13) + a.insert(1) + a.insert(6) + a.insert(7) + a.insert(4) + assert a.contains(100) is False + + +def test_search_5(): + """Test the search function.""" + a = BinarySearchTree() + a.insert(5) + assert a.search(5) == a.root + + +def test_search_10(): + """Test the search function.""" + a = BinarySearchTree() + a.insert(5) + a.insert(10) + assert a.search(10) == a.root.right + + +def test_search_empty(): + """Test the search function.""" + a = BinarySearchTree() + assert a.search(5) is None + + +def test_search_none(): + """Test the search function.""" + a = BinarySearchTree() + a.insert(8) + a.insert(10) + a.insert(3) + a.insert(14) + a.insert(13) + a.insert(1) + a.insert(6) + a.insert(7) + a.insert(4) + assert a.search(100) is None + + +def test_depth_zero(): + """Test the depth function.""" + a = BinarySearchTree() + assert a.depth() == 0 + + +def test_depth_one(): + """Test the depth function.""" + a = BinarySearchTree() + a.insert(8) + assert a.depth() == 1 + + +def test_depth_many(): + """Test the depth function.""" + a = BinarySearchTree() + a.insert(8) + a.insert(10) + a.insert(3) + a.insert(14) + a.insert(13) + a.insert(1) + a.insert(6) + a.insert(7) + a.insert(4) + assert a.depth() == 4 + + +def test_balance(): + """Test the balance function.""" + a = BinarySearchTree() + a.insert(8) + a.insert(10) + a.insert(3) + a.insert(14) + a.insert(13) + a.insert(1) + a.insert(6) + a.insert(7) + assert a.balance() == 0 + + +def test_balance_unbalanced_right(filled_bst): + """Test the balance function.""" + filled_bst.insert(11) + filled_bst.insert(12) + assert filled_bst.balance() == 2 + + +def test_balance_unbalanced_left(filled_bst): + """Test the balance function.""" + filled_bst.insert(5) + filled_bst.insert(4.5) + assert filled_bst.balance() == -2 + + +def test_in_order_traversal_first_node_traversed_is_1(filled_bst): + """In-order traversal will start with 1.""" + in_order_list = [] + for x in filled_bst._in_order_trav(): + in_order_list.append(x) + assert in_order_list[0] == 1 + + +def test_in_order_traversal_first_node_traversed_is_1_reg(filled_bst): + """In-order traversal's first value from generator will get a 1.""" + assert filled_bst.in_order() == 1 + assert filled_bst.in_order() == 3 + assert filled_bst.in_order() == 4 + assert filled_bst.in_order() == 6 + assert filled_bst.in_order() == 7 + assert filled_bst.in_order() == 8 + assert filled_bst.in_order() == 10 + assert filled_bst.in_order() == 13 + assert filled_bst.in_order() == 14 + + +def test_pre_order_traversal_first_node_traversed_is_8(filled_bst): + """Pre-order traversal will get 8.""" + assert filled_bst.pre_order() == 8 + assert filled_bst.pre_order() == 3 + assert filled_bst.pre_order() == 1 + assert filled_bst.pre_order() == 6 + assert filled_bst.pre_order() == 4 + assert filled_bst.pre_order() == 7 + assert filled_bst.pre_order() == 10 + assert filled_bst.pre_order() == 14 + assert filled_bst.pre_order() == 13 + + +def test_post_order_traversal(filled_bst): + """Post-order traversal.""" + assert filled_bst.post_order() == 1 + assert filled_bst.post_order() == 4 + assert filled_bst.post_order() == 7 + assert filled_bst.post_order() == 6 + assert filled_bst.post_order() == 3 + assert filled_bst.post_order() == 13 + assert filled_bst.post_order() == 14 + assert filled_bst.post_order() == 10 + assert filled_bst.post_order() == 8 + + +def test_delete_empty(): + """Test delete function with empty binary search tree.""" + a = BinarySearchTree() + assert a.delete(5) is None + + +def test_delete_filled_root(filled_bst): + """Test delete of root.""" + a = filled_bst + assert a.size() == 9 + a.delete(8) + assert a.size() == 8 + assert a.in_order() == 1 + assert a.in_order() == 3 + assert a.in_order() == 4 + assert a.in_order() == 6 + assert a.in_order() == 7 + assert a.in_order() == 10 + assert a.in_order() == 13 + assert a.in_order() == 14 + + +def test_delete_end(filled_bst): + """Test delete of root.""" + a = filled_bst + assert a.size() == 9 + a.delete(1) + assert a.size() == 8 + assert a.in_order() == 3 + assert a.in_order() == 4 + assert a.in_order() == 6 + assert a.in_order() == 7 + assert a.in_order() == 8 + assert a.in_order() == 10 + assert a.in_order() == 13 + assert a.in_order() == 14 + + +def test_delete_vertex_of_left_sub_head_in_bst(filled_bst): + """Test delete of a BST's left sub tree's head.""" + a = filled_bst + a.delete(3) + assert a.root.value == 8 + assert a.root.left.value == 4 + assert a.root.left.right.value == 6 + assert a.root.left.right.right.value == 7 + + +def test_delete_vertex_of_lower_vertex_with_2_children(filled_bst): + """Test lower vertex removal at bottom of tree with 2 children.""" + a = filled_bst + a.delete(6) + assert a.root.value == 8 + assert a.root.left.right.value == 7 + assert a.root.left.right.left.value == 4 + assert a.root.left.value == 3 + assert a.root.left.left.value == 1 + assert a.root.right.value == 10 + + +def test_delete(straight_bst): + """Test removal of node from straight line bst.""" + a = straight_bst + a.delete(4) + assert a.root.value == 1 + assert a.root.right.value == 2 + assert a.root.right.right.value == 3 + assert a.root.right.right.right.value == 5 + assert a.root.right.right.right.right.value == 6 + + +def test_node_deletion_from_big_tree_with_grand_children(big_bst): + """Test deletion of node in big bst tree with children and grand children.""" + a = big_bst + a.delete(45) + assert a.root.right.left.value == 46 + assert a.root.right.left.right.value == 47 + assert a.root.right.left.left.value == 42 + assert a.root.right.left.right.right.value == 49 + assert a.root.right.left.right.left is None + + +def test_deletion_from_big_tree_with_great_grand_children(big_bst): + """Test deletion of node in big bst tree with children and grand children.""" + a = big_bst + a.delete(50) + assert a.root.right.value == 52 + assert a.root.right.left.value == 45 + assert a.root.right.right.value == 60 + assert a.root.right.right.left.value == 55 + assert a.root.right.right.right.value == 65 + assert a.root.right.right.left.right.value == 57 + assert a.root.right.right.left.left is None + assert a.root.right.right.right.right.value == 70 + assert a.root.right.right.right.left.value == 63 + + +def test_node_deletion_from_big_tree_root(big_bst): + """Test root deletion on big_bst.""" + a = big_bst + a.delete(30) + assert a.root.value == 40 + assert a.root.right.value == 50 + assert a.root.right.left.value == 45 + assert a.root.right.left.left.value == 42 + assert a.root.right.left.left.left is None + assert a.root.right.left.left.right.value == 44 + assert a.root.right.right.value == 60 + assert a.root.right.right.left.value == 55 + assert a.root.right.right.right.value == 65 + assert a.root.right.right.left.right.value == 57 + assert a.root.right.right.left.left.value == 52 + assert a.root.right.right.right.right.value == 70 + assert a.root.right.right.right.left.value == 63 + + +def test_node_deletion_from_big_tree_furthest_left(big_bst): + """Test furthest left node deletion on big_bst.""" + a = big_bst + a.delete(4) + assert a.root.value == 30 + assert a.root.left.value == 15 + assert a.root.left.left.value == 10 + assert a.root.left.left.left.value == 7 + assert a.root.left.left.left.left is None + assert a.root.right.value == 50 + assert a.root.right.left.value == 45 + assert a.root.right.left.left.value == 42 + assert a.root.right.left.left.left.value == 40 + assert a.root.right.left.left.right.value == 44 + assert a.root.right.right.value == 60 + assert a.root.right.right.left.value == 55 + assert a.root.right.right.right.value == 65 + assert a.root.right.right.left.right.value == 57 + assert a.root.right.right.left.left.value == 52 + assert a.root.right.right.right.right.value == 70 + assert a.root.right.right.right.left.value == 63 + + +def test_big_bst(big_bst): + """Test nodes in proper places in big_bst.""" + a = big_bst + assert a.root.value == 30 + assert a.root.left.value == 15 + assert a.root.left.right.value == 25 + assert a.root.left.right.left.value == 23 + assert a.root.left.left.value == 10 + assert a.root.left.left.right.value == 12 + assert a.root.left.left.right.right.value == 13 + assert a.root.left.left.right.left.value == 11 + assert a.root.left.left.left.value == 7 + assert a.root.left.left.left.right.value == 9 + assert a.root.left.left.left.left.value == 4 + assert a.root.right.value == 50 + assert a.root.right.left.value == 45 + assert a.root.right.left.left.value == 42 + assert a.root.right.left.left.left.value == 40 + assert a.root.right.left.left.right.value == 44 + assert a.root.right.right.value == 60 + assert a.root.right.right.left.value == 55 + assert a.root.right.right.right.value == 65 + assert a.root.right.right.left.right.value == 57 + assert a.root.right.right.left.left.value == 52 + assert a.root.right.right.right.right.value == 70 + assert a.root.right.right.right.left.value == 63 + + +def test_big_bst_insert_delete_min_node_with_right_child(big_bst): + """Test deletion of node with min node with right child.""" + a = big_bst + a.insert(22) + a.delete(15) + assert a.root.value == 30 + assert a.root.left.value == 21 + assert a.root.left.right.value == 25 + assert a.root.left.right.left.value == 23 + assert a.root.left.right.left.left.value == 22 + assert a.root.left.left.value == 10 + assert a.root.left.left.right.value == 12 + assert a.root.left.left.right.right.value == 13 + assert a.root.left.left.right.left.value == 11 + assert a.root.left.left.left.value == 7 + assert a.root.left.left.left.right.value == 9 + assert a.root.left.left.left.left.value == 4 + assert a.root.right.value == 50 + assert a.root.right.left.value == 45 + assert a.root.right.left.left.value == 42 + assert a.root.right.left.left.left.value == 40 + assert a.root.right.left.left.right.value == 44 + assert a.root.right.right.value == 60 + assert a.root.right.right.left.value == 55 + assert a.root.right.right.right.value == 65 + assert a.root.right.right.left.right.value == 57 + assert a.root.right.right.left.left.value == 52 + assert a.root.right.right.right.right.value == 70 + assert a.root.right.right.right.left.value == 63 + + +def test_big_bst_insert_delete_root_min_node_with_right_child(big_bst): + """Test deletion of root node with min node with right child.""" + a = big_bst + a.insert(41) + a.delete(30) + a = big_bst + assert a.root.value == 40 + assert a.root.left.value == 15 + assert a.root.left.right.value == 25 + assert a.root.left.right.left.value == 23 + assert a.root.left.left.value == 10 + assert a.root.left.left.right.value == 12 + assert a.root.left.left.right.right.value == 13 + assert a.root.left.left.right.left.value == 11 + assert a.root.left.left.left.value == 7 + assert a.root.left.left.left.right.value == 9 + assert a.root.left.left.left.left.value == 4 + assert a.root.right.value == 50 + assert a.root.right.left.value == 45 + assert a.root.right.left.left.value == 42 + assert a.root.right.left.left.left.value == 41 + assert a.root.right.left.left.right.value == 44 + assert a.root.right.right.value == 60 + assert a.root.right.right.left.value == 55 + assert a.root.right.right.right.value == 65 + assert a.root.right.right.left.right.value == 57 + assert a.root.right.right.left.left.value == 52 + assert a.root.right.right.right.right.value == 70 + assert a.root.right.right.right.left.value == 63 + + +def test_multiple_delete_to_empty(filled_bst): + """Test that all nodes can be deleted and size output reflects this.""" + a = filled_bst + a.delete(8) + a.delete(10) + a.delete(3) + a.delete(14) + a.delete(13) + a.delete(1) + a.delete(6) + a.delete(7) + a.delete(4) + assert a.size() == 0 diff --git a/src/test_hash_table.py b/src/test_hash_table.py new file mode 100644 index 0000000..60e1e16 --- /dev/null +++ b/src/test_hash_table.py @@ -0,0 +1,4 @@ +"""Test module for Hash Table.""" + +from hash_table import HashTable +import pytest