def test_node_balance_factor(self): data = [1, 2] avl_tree = AVLTree(data) assert avl_tree.root.balance_factor() == -1 data = [2, 1] avl_tree = AVLTree(data) assert avl_tree.root.balance_factor() == 1
def test_smaller_entry_on_the_left_of_root(self): tree = AVLTree() tree.insert(9) tree.insert(4) self.assertEqual(tree.root.entry, 9) self.assertEqual(tree.root.left.entry, 4)
def test_single_right_rotation_1(self): data = [3, 2, 1] avl_tree = AVLTree(data) assert avl_tree.root.data == 2 assert avl_tree.root.left_child.data == 1 assert avl_tree.root.right_child.data == 3 assert avl_tree.items_level_order() == [2, 1, 3]
def test_delete_single_element(self): tree = AVLTree([1]) tree.delete(1) self.assertNotIn(1, tree) self.assertFalse(tree) self.assertEqual(len(tree), 0)
def test_insert_on_empty_tree(self): tree = AVLTree() tree.insert(9) self.assertEqual(tree.root.entry, 9) self.assertEqual(tree.root.left.balance_factor, 0) self.assertEqual(tree.root.right.balance_factor, 0) self.assertTrue(tree)
def test_delete_leaf_node(self): tree = AVLTree([1, 2]) tree.delete(2) self.assertIn(1, tree) self.assertNotIn(2, tree) self.assertTrue(tree) self.assertEqual(len(tree), 1)
def test_delete_entry_make_tree_unbalanced(self): entries = [5, 3, 8, 2, 4, 7, 11, 1, 6, 10, 12, 9] tree = AVLTree(entries) entry_to_be_deleted = 4 tree.delete(entry_to_be_deleted) expected_order = (8, 5, 11, 2, 7, 10, 12, 1, 3, 6, 9) self.assertNotIn(entry_to_be_deleted, tree) self.assertTupleEqual(tuple(tree.traverse('bfs')), expected_order)
def test_delete_entry_but_tree_remains_balanced(self): entries = [10, 5, 11, 3, 7, 15] tree = AVLTree(entries) entry_to_be_deleted = 10 tree.delete(entry_to_be_deleted) expected_order = (7, 5, 11, 3, 15) self.assertNotIn(entry_to_be_deleted, tree) self.assertTupleEqual(tuple(tree.traverse('bfs')), expected_order)
def test_length(self): tree = AVLTree() entries = range(150) for entry in entries: tree.insert(entry) with self.subTest("test non-empty tree"): self.assertEqual(len(tree), len(entries)) with self.subTest("test empty tree"): self.assertEqual(len(AVLTree()), 0)
def test_rightRotationOnRoot(self): tree = AVLTree() tree.insert(3) tree.insert(2) tree.insert(1) tree.root = tree.right_rotation(tree.root) nodes = tree.preorder_traversal() self.assertEqual(nodes, [2, 1, 3])
def test_insertPreOrderWithRootAndLeftRightNodesWithLevel1Children(self): tree = AVLTree() tree.insert(4) tree.insert(3) tree.insert(1) tree.insert(2) tree.insert(5) nodes = tree.preorder_traversal() self.assertEqual(nodes, [4, 3, 1, 2, 5])
def test_heightRootNodeLeftRight3LevelChildren(self): tree = AVLTree() tree.insert(4) tree.insert(5) tree.insert(2) tree.insert(3) tree.insert(1) height = tree.get_height(tree.root) self.assertEqual(height, 3)
def test_empty_traversal(self): tree = AVLTree() d = { 'preorder': (), 'inorder': (), 'postorder': (), 'bfs': (), } for order, expected_value in d.items(): with self.subTest(f"test {order}"): self.assertTupleEqual(tuple(tree.traverse(order)), expected_value)
def test_node_update_height(self): data = [1, 2] avl_tree = AVLTree(data) assert avl_tree.root.data == 1 assert avl_tree.root.height == 1 assert avl_tree.root.left_child == None assert avl_tree.root.right_child.height == 0 avl_tree.insert(3) assert avl_tree.root.data == 2 assert avl_tree.root.height == 1 assert avl_tree.root.left_child.data == 1 assert avl_tree.root.left_child.height == 0 assert avl_tree.root.right_child.data == 3 assert avl_tree.root.right_child.height == 0
def test_right_left_rotation(self): tree = AVLTree() tree.insert(1) root = tree.root self.assertEqual(root.balance_factor, 0) self.assertEqual(root.height, 1) self.assertEqual(root.entry, 1) tree.insert(3) root = tree.root self.assertEqual(root.balance_factor, -1) self.assertEqual(root.height, 2) self.assertEqual(root.entry, 1) self.assertEqual(root.right.entry, 3) tree.insert(2) root = tree.root self.assertEqual(root.balance_factor, 0) self.assertEqual(root.left.balance_factor, 0) self.assertEqual(root.right.balance_factor, 0) self.assertEqual(root.height, 2) self.assertEqual(root.entry, 2) self.assertEqual(root.left.entry, 1) self.assertEqual(root.right.entry, 3)
def test_initialize_tree_from_sequence(self): import math entries = [1, 2, 3, 4, 5, 6, 7] tree = AVLTree(entries) expected_order = (4, 2, 6, 1, 3, 5, 7) with self.subTest( f"bfs traversal must be have this order {expected_order}."): self.assertTupleEqual(tuple(tree.traverse('bfs')), expected_order) with self.subTest(f"tree must have {len(entries)} entries."): self.assertEqual(len(tree), len(entries)) with self.subTest( f"tree must have {math.ceil(math.log2(len(entries)))} height." ): self.assertEqual(tree.height, math.ceil(math.log2(len(entries))))
def getResults(): """ Return search results """ searchQuery = request.args.get('word') if not searchQuery: return json.dumps([]) t = AVLTree() treeSearch.search(searchQuery, 3, t) return json.dumps(t.inorder_traverse())
def test_search_complex_data_type(self): tree = AVLTree([ Entry(1, 'a'), Entry(2, 'b'), Entry(3, 'c'), Entry(3, 'd'), ]) entry = tree.search(Entry(3, 'd')) self.assertEqual(Entry(3, 'd'), entry) entry = Entry(3113, 'd') with self.assertRaises(KeyError) as context: tree.search(entry) self.assertIn(f"Entry {entry} not found.", str(context.exception))
def gen_balanced_tree(range_bounds=DEFAULT_RANGE_BOUNDS, value_bounds=DEFAULT_VALUE_BOUNDS): """ Generate a balanced AVLTree from random data """ tree = AVLTree() return fill_random_tree(tree, range_bounds, value_bounds)
def test_insert_remove( size ): # test tree from random, delete, and rebalance, setitem with existing key lbase = list(range(0, size)) random.shuffle(lbase) # randomize dref = {} tree = AVLTree() for key in lbase: v = random.choice(lbase) tree[key] = v dref[key] = v assert_true( dict_to_sorted_pairs(dref) == list(tree), f"random tree did not match reference") assert_true( is_balanced(tree), f"1 tree is not balanced after inserting {size} random keys/values" ) assert_true( dict_to_sorted_pairs(dref) == list(tree), f"random tree did not match reference") deleted_keys = random.sample(lbase, size // 2) for key in deleted_keys: # delete half of original del tree[key] del dref[key] assert_true(is_balanced(tree), f"tree is not balanced after deleting key:{key} ") assert_true( dict_to_sorted_pairs(dref) == list(tree), f"random tree did not match reference")
def test_balanced_tree1(self): """ Test against a balanced binary tree """ values = [1, 2, 3] tree, _ = fill_tree(AVLTree(), values) actual = tree_is_balanced(tree) self.assertTrue(actual)
def build_avl(alist): avl_tree = AVLTree() #line by line splits in order to check if the word starts with an alpha char or not for i in range(len(alist)): temp_a = alist[i].split(" ") temp_w = temp_a[0] #if it is an alpha char it will create a new list for the embedding and create a node if temp_w.isalpha(): embedding = [] for j in range(len(temp_a - 1)): embedding.append(temp_a[j + 1]) temp_n = Node(temp_w, embedding) avl_tree.insert(temp_n)
def test_equals(self): tree1 = AVLTree([1, 2, 3, 4, 5]) tree2 = AVLTree([2, 1, 4, 3, 5]) tree3 = AVLTree([1, 2, 3, 4, 5, 6]) with self.subTest(f"test equal trees"): self.assertEqual(tree1, tree2) self.assertFalse(tree1 is tree2) with self.subTest(f"test different trees"): self.assertNotEqual(tree1, tree3) self.assertFalse(tree1 is tree3) self.assertNotEqual(tree2, tree3) self.assertFalse(tree2 is tree3) with self.subTest(f"test tree is different from other classes"): self.assertNotEqual(tree1, int(9)) with self.subTest(f"test tree is different from empty tree"): self.assertNotEqual(tree1, AVLTree())
def compare_tree_expected(self, values: list): """ Helper function that sorts the given list and compares the result to an inorder traversal of the AVL. """ expected = sorted(values) actual = AVLTree(values).traverse() self.assertEqual(expected, actual)
def test_insert_duplicated_entry(self): tree = AVLTree() tree.insert(9) tree.insert(10) tree.insert(9) self.assertEqual(tree.root.entry, 9) self.assertEqual(tree.root.right.entry, 10) self.assertEqual(tree.height, 2) self.assertTrue(tree)
def test_insertPreOrderWithRootAndLeftRightNodes(self): tree = AVLTree() tree.insert(4) tree.insert(3) tree.insert(5) nodes = tree.preorder_traversal() self.assertEqual(nodes, [4, 3, 5])
def test_update_height(self): self.assertEqual(self.tree.height, -1) self.tree.node = Node(5) self.tree.update_height() self.assertEqual(self.tree.height, 0) self.tree.node.left = AVLTree(Node(3)) self.tree.update_height() self.assertEqual(self.tree.node.left.height, 0) self.assertEqual(self.tree.height, 1) self.tree.node.right = AVLTree(Node(6)) self.tree.update_height() self.assertEqual(self.tree.height, 1) self.tree.node.right.node.right = AVLTree(Node(8)) self.tree.update_height() self.assertEqual(self.tree.height, 2)
def test_avl_insertion(): """Tests that avl insertion maintains balance""" bintree = AVLTree() for i in xrange(100): bintree.insert(random.randint(0, 1e6)) assert bintree.size() == 100 assert abs(bintree.balance()) < 2 assert bintree.depth() < 9 # 2 ** 7 is 128, it should fit
def test_insert_with_left_right_rotation(self): number = [10, 1, 5] avlTree = AVLTree(numbers) assert avlTree.root.number == 5 assert avlTree.root.left.number == 1 assert avlTree.root.left.number == 10 assert avlTree.root.height = 1 assert avlTree.root.left.height = 2 assert avlTree.root.right.height = 2
def test_insert_with_left_left_rotation(self): number = [14, 20, 16] avlTree = AVLTree(numbers) assert avlTree.root.number == 16 assert avlTree.root.left.number == 14 assert avlTree.root.left.number == 20 assert avlTree.root.height = 1 assert avlTree.root.left.height = 2 assert avlTree.root.right.height = 2
def test_avl_deletion(): """Tests that avl deletion maintains balance""" bintree = AVLTree() bintree.insert(10) bintree.insert(5) bintree.insert(15) bintree.insert(2) bintree.insert(7) bintree.insert(12) bintree.insert(30) bintree.insert(1) bintree.insert(11) bintree.insert(13) bintree.insert(35) bintree.insert(14) # 10 # / \ # 5 15 # / \ / \ # 2 7 12 30 # / / \ \ # 1 11 13 35 # \ # 14 # All inserted in an order such that no rotations occurred assert bintree.depth() == 5 assert bintree.balance() == -1 assert bintree.size() == 12 bintree.delete(15) # 10 # / \ # 5 14 # / \ / \ # 2 7 12 30 # / / \ \ # 1 11 13 35 # This is standard deletion, still in balance. # check that balance/depth update correctly assert bintree.balance() == 0 assert bintree.depth() == 4 assert bintree.size() == 11 assert bintree.rightchild.depth() == 3 assert bintree.rightchild.leftchild.depth() == 2 assert bintree.rightchild.leftchild.balance() == 0 # used to be -1 bintree.delete(7) # 10 # / \ # 5 14 # / / \ # 2 12 30 # / / \ \ # 1 11 13 35 # Now 5 is out of balance, rotate left up # 10 # / \ # 2 14 # / \ / \ # 1 5 12 30 # / \ \ # 11 13 35 assert bintree.leftchild.value == 2 assert bintree.balance() == -1 assert bintree.depth() == 4 assert bintree.leftchild.depth() == 2 assert bintree.leftchild.rightchild.depth() == 1 bintree.delete(10) # 11 # / \ # 2 14 # / \ / \ # 1 5 12 30 # \ \ # 13 35 # Just normal deletion bintree.delete(11) # 12 # / \ # 2 14 # / \ / \ # 1 5 13 30 # \ # 35 # Just normal deletion bintree.delete(12) # 13 # / \ # 2 14 # / \ \ # 1 5 30 # \ # 35 # Now 14 is out of balance, rotate 30 up # 13 # / \ # 2 30 # / \ / \ # 1 5 14 35 assert bintree.depth() == 3 assert bintree.balance() == 0 assert bintree.value == 13 assert bintree.leftchild.value == 2 assert bintree.rightchild.value == 30 assert bintree.leftchild.depth() == 2 assert bintree.rightchild.depth() == 2
def process_tree(prev_info, build_first): for_tree_build = list() for_tree_build.append(get_dict(prev_info)) prev_x1 = float(prev_info[x1i]) ALL_XS.append([prev_x1, None]) next_info = f.readline().split() if next_info: next_x1 = float(next_info[x1i]) while prev_x1 == next_x1: for_tree_build.append(get_dict(next_info)) next_info = f.readline().split() next_x1 = float(next_info[x1i]) # середина между x(i) и x(i+1) для нахождений val-ов x_middle = (next_x1+prev_x1)/2 prev_to_delete = to_delete # обрабатываем ноды будущего дерева to_add = process_tree_nodes(for_tree_build, x_middle, next_info[x1i]) print '-'*80 print to_add print prev_to_delete if build_first: tree = AVLTree() for n in to_add: tree.add(tree.root, n['val'], n['a'], n['b'], n['pol_id']) tree.show() ref_to_tree = tree else: # если кривые координаты, идут вразброс с дырами, # то строим новое дерево # __ __ # / \ пустота / \ # \__/ \__/ if not prev_to_delete: print 'Hole' tree = AVLTree() for n in to_add: tree.add(tree.root, n['val'], n['a'], n['b'], n['pol_id']) tree.show() ref_to_tree = tree else: prev_tree = ALL_XS[-2][1] next_tree = deepcopy(prev_tree) # пока грубое добавление/удаление for n in to_add: next_tree.add(next_tree.root, n['val'], n['a'], n['b'], n['pol_id']) for n in prev_to_delete: next_tree.delete(n['val']) ref_to_tree = next_tree next_tree.show() ALL_XS[-1][1] = ref_to_tree return next_info # TODO обработать последнюю строку(последний x), # TODO а то теряется последнее дерево return None
def process_tree(row, main_file, err_del_nodes_old, del_nodes_old, is_holl): # находим ноды для нового дерева row_float = float(row['x1']) all_x2 = [float(row['x2']), ] print 'STAAAAAAAAAAAAAAAAAAAAAAAAAAAAAART' print 'is_holl', is_holl try: next_line = main_file.next() next_row = get_row_dict(next_line) print 'next_row', next_row next_float = float(next_row['x1']) except StopIteration: return None, 1, 1, 1 add_nodes = [row, ] while next_float == row_float: add_nodes.append(next_row) all_x2.append(float(next_row['x2'])) try: next_line = main_file.next() next_row = get_row_dict(next_line) next_float = float(next_row['x1']) except StopIteration: next_float = 181 break min_x2_float = min(all_x2) max_x2_float = max(all_x2) x_middle = (min_x2_float + row_float) / 2 # print 'all_x2', all_x2 # print 'x_middle', x_middle, 'prev_row', row_float, 'next_row', next_float prev_tree = ALL_XS[-1][1] next_tree = AVLTree() # l() # print 'prev_tree' # prev_tree.show() # l() print 'err_del_nodes_old', err_del_nodes_old l() print 'prev_tree' prev_tree.show() # l() print 'next_tree' next_tree.show() # актуализируем все значения новых нодов для добавления update_dict_vals(add_nodes, x_middle) # если предыдущее дерево пусто или между полигонами дыра if is_holl or prev_tree.root.val is None: for a in add_nodes: # print 'add', float(a['val']) next_tree.add(next_tree.root, float(a['val']), a['a'], a['b'], a['pol_id'], a['x2'], a['y2']) else: # удаляем ноды битые, у которых х2 меньше, чем следующий х1 for err_d in err_del_nodes_old: print 'delete err_del_node', float(err_d['val']) next_tree.delete_versionly(prev_tree, float(err_d['val'])) # 45.7427962225 print 'del_nodes_old', del_nodes_old # обработка нодов на замену/добавление/удаление to_replace, proc_del, proc_add = treatment_add_del(del_nodes_old, add_nodes) print 'proc_del', proc_del for d in proc_del: next_tree.delete_versionly(prev_tree, float(d['val'])) print 'to_replace', to_replace for (d, a) in to_replace: next_tree.replace_versionly(prev_tree, float(d['val']), a) # актуализируем все значения нодов в дереве next_tree.update_vals(x_middle) # актуализируем все значения новых нодов для добавления # update_dict_vals(proc_add, x_middle) print 'proc_add', proc_add # предыдущее дерево непусто, но новое дерево пусто, # и если мы удаляли уже, то без версионности if next_tree.root.val is None and (del_nodes_old or err_del_nodes_old): l() print 'next_tree.root.val is None and (del_nodes_old or err_del_nodes_old)!!!' for a in proc_add: # print 'add', a['val'] next_tree.add(next_tree.root, float(a['val']), a['a'], a['b'], a['pol_id'], a['x2'], a['y2']) # новое просто пусто(т.к. ничего не удадяли) или непусто, то версионность else: l() print 'next_tree.root.val is None or is not empty!!!' for a in proc_add: # print 'add_versionly', a['val'] next_tree.add_versionly(prev_tree, a) # обнуляем версионность дерева next_tree next_tree.remove_update_flags(next_tree.root) ALL_XS.append([float(row_float), next_tree]) err_del_nodes = [node for node in add_nodes if float(node['x2']) < next_float] print 'err_del_nodes', err_del_nodes # if err_del_nodes: # print 'Err_del_nodes exists', row_float, err_del_nodes del_nodes = [node for node in add_nodes if float(node['x2']) == next_float] print 'next_tree' next_tree.show() print 'EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEND' print 'max_x2_float', max_x2_float, 'next_float', next_float l() return next_row, err_del_nodes, del_nodes, max_x2_float < next_float
def test_rotations(): """Tests my rotations, balance, and depth with a simple AVLtree""" # Initialization etc. should work fine, just inherits from well-tested BST bintree = AVLTree() assert bintree.depth() == 0 with pytest.raises(ValueError): bintree._rotate_left() bintree.insert(5) assert bintree.depth() == 1 with pytest.raises(ValueError): bintree._rotate_left() with pytest.raises(ValueError): bintree._rotate_right() bintree.insert(3) assert bintree.depth() == 2 with pytest.raises(ValueError): bintree._rotate_right() # 3 is on left bintree._rotate_left() # 3 now head bintree._rotate_right() # 5 is head again bintree.insert(7) bintree.insert(6) bintree.insert(2) bintree.insert(4) bintree.insert(1) bintree.insert(9) bintree.insert(10) # All in order, no rotations done # 5 # / \ # 3 7 # /\ / \ # 2 4 6 9 # | | # 1 10 bintree._rotate_right() # 7 # / \ # 5 9 # | \ \ # 3 6 10 # /\ # 2 4 # | # 1 assert bintree.value == 7 assert bintree.balance() == 2 assert bintree.size() == 9 assert bintree.depth() == 5 assert bintree.rightchild.value == 9 assert bintree.leftchild.value == 5 assert bintree.leftchild.rightchild.value == 6 bintree.leftchild._rotate_left() # Note that this breaks stuff at head; the update of depth/_level is part # of insert()/delete(), so 7 never gets releveled without the next line bintree._relevel() # 7 # / \ # 3 9 # | \ \ # 2 5 10 # / / \ # 1 4 6 assert bintree.balance() == 1 assert bintree.depth() == 4 pivot_node = bintree.leftchild assert pivot_node.value == 3 assert pivot_node.leftchild.value == 2 assert pivot_node.rightchild.value == 5