From 0bc3eb2a8622943ff041f9a4fa4807bc7d5fb390 Mon Sep 17 00:00:00 2001 From: Kishan Ved Date: Thu, 6 Jun 2024 13:03:58 +0530 Subject: [PATCH] C++ backend for Self Balancing Binary Tree (#559) --- .../_backend/cpp/stack/ArrayStack.hpp | 1 - .../_backend/cpp/BinaryTreeTraversal.hpp | 9 +- .../_backend/cpp/SelfBalancingBinaryTree.hpp | 287 ++++++++++++++++++ pydatastructs/trees/_backend/cpp/trees.cpp | 7 + pydatastructs/trees/binary_trees.py | 9 + .../trees/tests/test_binary_trees.py | 20 +- 6 files changed, 328 insertions(+), 5 deletions(-) create mode 100644 pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp diff --git a/pydatastructs/miscellaneous_data_structures/_backend/cpp/stack/ArrayStack.hpp b/pydatastructs/miscellaneous_data_structures/_backend/cpp/stack/ArrayStack.hpp index eb4a27fe0..36633c084 100644 --- a/pydatastructs/miscellaneous_data_structures/_backend/cpp/stack/ArrayStack.hpp +++ b/pydatastructs/miscellaneous_data_structures/_backend/cpp/stack/ArrayStack.hpp @@ -4,7 +4,6 @@ #define PY_SSIZE_T_CLEAN #include #include -#include #include #include "../../../../linear_data_structures/_backend/cpp/arrays/DynamicOneDimensionalArray.hpp" diff --git a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index a20e6b5aa..5c464787c 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp @@ -13,6 +13,7 @@ #include "../../../linear_data_structures/_backend/cpp/arrays/ArrayForTrees.hpp" #include "BinaryTree.hpp" #include "BinarySearchTree.hpp" +#include "SelfBalancingBinaryTree.hpp" typedef struct { PyObject_HEAD @@ -32,7 +33,13 @@ static PyObject* BinaryTreeTraversal___new__(PyTypeObject* type, PyObject *args, if (PyType_Ready(&BinarySearchTreeType) < 0) { // This has to be present to finalize a type object. This should be called on all type objects to finish their initialization. return NULL; } - if (PyObject_IsInstance(tree, (PyObject *)&BinarySearchTreeType)) { + if (PyType_Ready(&SelfBalancingBinaryTreeType) < 0) { // This has to be present to finalize a type object. This should be called on all type objects to finish their initialization. + return NULL; + } + if (PyObject_IsInstance(tree, (PyObject *)&SelfBalancingBinaryTreeType)) { + self->tree = reinterpret_cast(tree)->bst->binary_tree; + } + else if (PyObject_IsInstance(tree, (PyObject *)&BinarySearchTreeType)) { self->tree = reinterpret_cast(tree)->binary_tree; } else { diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp new file mode 100644 index 000000000..f499c9bf0 --- /dev/null +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -0,0 +1,287 @@ +#ifndef TREES_SELFBALANCINGSelfBalancingBinaryTree_HPP +#define TREES_SELFBALANCINGSelfBalancingBinaryTree_HPP + +#define PY_SSIZE_T_CLEAN +#include +#include +#include +#include "../../../utils/_backend/cpp/utils.hpp" +#include "../../../utils/_backend/cpp/TreeNode.hpp" +#include "../../../linear_data_structures/_backend/cpp/arrays/ArrayForTrees.hpp" +#include "../../../linear_data_structures/_backend/cpp/arrays/DynamicOneDimensionalArray.hpp" +#include "BinarySearchTree.hpp" + +typedef struct { + PyObject_HEAD + BinarySearchTree* bst; + ArrayForTrees* tree; +} SelfBalancingBinaryTree; + +static void SelfBalancingBinaryTree_dealloc(SelfBalancingBinaryTree *self) { + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +static PyObject* SelfBalancingBinaryTree___new__(PyTypeObject* type, PyObject *args, PyObject *kwds) { + SelfBalancingBinaryTree *self; + self = reinterpret_cast(type->tp_alloc(type, 0)); + + if (PyType_Ready(&BinarySearchTreeType) < 0) { // This has to be present to finalize a type object. This should be called on all type objects to finish their initialization. + return NULL; + } + PyObject* p = BinarySearchTree___new__(&BinarySearchTreeType, args, kwds); + self->bst = reinterpret_cast(p); + self->tree = reinterpret_cast(p)->binary_tree->tree; + + return reinterpret_cast(self); +} + +static PyObject* SelfBalancingBinaryTree___str__(SelfBalancingBinaryTree *self) { + return BinarySearchTree___str__(self->bst); +} + +static PyObject* SelfBalancingBinaryTree_insert(SelfBalancingBinaryTree* self, PyObject* args) { + return BinarySearchTree_insert(self->bst, args); +} + +static PyObject* SelfBalancingBinaryTree_search(SelfBalancingBinaryTree* self, PyObject *args, PyObject *kwds) { + return BinarySearchTree_search(self->bst, args, kwds); +} + +static PyObject* SelfBalancingBinaryTree_delete(SelfBalancingBinaryTree* self, PyObject *args, PyObject *kwds) { + return BinarySearchTree_delete(self->bst, args, kwds); +} + +static PyObject* SelfBalancingBinaryTree_lower_bound(SelfBalancingBinaryTree* self, PyObject *args, PyObject *kwds) { + return BinarySearchTree_lower_bound(self->bst, args, kwds); +} + +static PyObject* SelfBalancingBinaryTree_upper_bound(SelfBalancingBinaryTree* self, PyObject *args, PyObject *kwds) { + return BinarySearchTree_upper_bound(self->bst, args, kwds); +} + +static PyObject* SelfBalancingBinaryTree__simple_path(SelfBalancingBinaryTree* self, PyObject *args) { + return BinarySearchTree__simple_path(self->bst, args); +} + +static PyObject* SelfBalancingBinaryTree__lca_1(SelfBalancingBinaryTree* self, PyObject *args) { + return BinarySearchTree__simple_path(self->bst, args); +} + +static PyObject* SelfBalancingBinaryTree__lca_2(SelfBalancingBinaryTree* self, PyObject *args) { + return BinarySearchTree__simple_path(self->bst, args); +} + +static PyObject* SelfBalancingBinaryTree_lowest_common_ancestor(SelfBalancingBinaryTree* self, PyObject *args) { + return BinarySearchTree_lowest_common_ancestor(self->bst, args); +} + +static PyObject* SelfBalancingBinaryTree_rank(SelfBalancingBinaryTree* self, PyObject *args) { + return BinarySearchTree_rank(self->bst, args); +} + +static PyObject* SelfBalancingBinaryTree_select(SelfBalancingBinaryTree* self, PyObject *args) { + return BinarySearchTree_select(self->bst, args); +} + +static PyObject* SelfBalancingBinaryTree__right_rotate(SelfBalancingBinaryTree* self, PyObject *args) { + PyObject* j = PyObject_GetItem(args, PyZero); + PyObject* k = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->bst->binary_tree; + PyObject* y = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->right; + if (y != Py_None) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(y)])->parent = j; + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->left = y; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent != Py_None) { + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent)])->left == j) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent)])->left = k; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent)])->right = k; + } + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent = k; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->right = j; + PyObject* kp = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent; + if (kp == Py_None) { + bt->root_idx = k; + } + Py_RETURN_NONE; +} + +static PyObject* SelfBalancingBinaryTree__left_rotate(SelfBalancingBinaryTree* self, PyObject *args) { + PyObject* j = PyObject_GetItem(args, PyZero); + PyObject* k = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->bst->binary_tree; + PyObject* y = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->left; + if (y != Py_None) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(y)])->parent = j; + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->right = y; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent != Py_None) { + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent)])->left == j) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent)])->left = k; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent)])->right = k; + } + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent = k; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->left = j; + PyObject* kp = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent; + if (kp == Py_None) { + bt->root_idx = k; + } + Py_RETURN_NONE; +} + +static PyObject* SelfBalancingBinaryTree__left_right_rotate(SelfBalancingBinaryTree* self, PyObject *args) { + PyObject* j = PyObject_GetItem(args, PyZero); + PyObject* k = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->bst->binary_tree; + + PyObject* i = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->right; + PyObject* v = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->left; + PyObject* w = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->right; + + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->right = v; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->left = w; + + if (v != Py_None) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(v)])->parent = k; + } + if (w != Py_None) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(w)])->parent = j; + } + + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->left = k; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->right = j; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->parent = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent; + + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent = i; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent = i; + + PyObject* ip = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->parent; + if (ip != Py_None) { + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(ip)])->left == j) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(ip)])->left = i; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(ip)])->right = i; + } + } + else { + bt->root_idx = i; + } + Py_RETURN_NONE; +} + +static PyObject* SelfBalancingBinaryTree__right_left_rotate(SelfBalancingBinaryTree* self, PyObject *args) { + PyObject* j = PyObject_GetItem(args, PyZero); + PyObject* k = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->bst->binary_tree; + + PyObject* i = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->left; + PyObject* v = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->left; + PyObject* w = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->right; + + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->left = w; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->right = v; + + if (v != Py_None) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(v)])->parent = j; + } + if (w != Py_None) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(w)])->parent = k; + } + + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->right = k; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->left = j; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->parent = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent; + + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->parent = i; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->parent = i; + + PyObject* ip = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(i)])->parent; + if (ip != Py_None) { + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(ip)])->left == j) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(ip)])->left = i; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(ip)])->right = i; + } + } + else { + bt->root_idx = i; + } + Py_RETURN_NONE; +} + +static struct PyMethodDef SelfBalancingBinaryTree_PyMethodDef[] = { + {"insert", (PyCFunction) SelfBalancingBinaryTree_insert, METH_VARARGS | METH_KEYWORDS, NULL}, + {"delete", (PyCFunction) SelfBalancingBinaryTree_delete, METH_VARARGS | METH_KEYWORDS, NULL}, + {"search", (PyCFunction) SelfBalancingBinaryTree_search, METH_VARARGS | METH_KEYWORDS, NULL}, + {"lower_bound", (PyCFunction) SelfBalancingBinaryTree_lower_bound, METH_VARARGS | METH_KEYWORDS, NULL}, + {"upper_bound", (PyCFunction) SelfBalancingBinaryTree_upper_bound, METH_VARARGS | METH_KEYWORDS, NULL}, + {"_simple_path", (PyCFunction) SelfBalancingBinaryTree__simple_path, METH_VARARGS, NULL}, + {"_lca_1", (PyCFunction) SelfBalancingBinaryTree__lca_1, METH_VARARGS, NULL}, + {"_lca_2", (PyCFunction) SelfBalancingBinaryTree__lca_2, METH_VARARGS, NULL}, + {"lowest_common_ancestor", (PyCFunction) SelfBalancingBinaryTree_lowest_common_ancestor, METH_VARARGS, NULL}, + {"rank", (PyCFunction) SelfBalancingBinaryTree_rank, METH_VARARGS, NULL}, + {"select", (PyCFunction) SelfBalancingBinaryTree_select, METH_VARARGS, NULL}, + {"_right_rotate", (PyCFunction) SelfBalancingBinaryTree__right_rotate, METH_VARARGS, NULL}, + {"_left_rotate", (PyCFunction) SelfBalancingBinaryTree__left_rotate, METH_VARARGS, NULL}, + {"_left_right_rotate", (PyCFunction) SelfBalancingBinaryTree__left_right_rotate, METH_VARARGS, NULL}, + {"_right_left_rotate", (PyCFunction) SelfBalancingBinaryTree__right_left_rotate, METH_VARARGS, NULL}, + {NULL} +}; + +static PyMemberDef SelfBalancingBinaryTree_PyMemberDef[] = { + {"tree", T_OBJECT_EX, offsetof(SelfBalancingBinaryTree, tree), 0, "tree"}, + {NULL} /* Sentinel */ +}; + + +static PyTypeObject SelfBalancingBinaryTreeType = { + /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "SelfBalancingBinaryTree", + /* tp_basicsize */ sizeof(SelfBalancingBinaryTree), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor) SelfBalancingBinaryTree_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_reserved */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ (reprfunc) SelfBalancingBinaryTree___str__, + /* tp_getattro */ 0, + /* tp_setattro */ 0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + /* tp_doc */ 0, + /* tp_traverse */ 0, + /* tp_clear */ 0, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ SelfBalancingBinaryTree_PyMethodDef, + /* tp_members */ SelfBalancingBinaryTree_PyMemberDef, + /* tp_getset */ 0, + /* tp_base */ &BinarySearchTreeType, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ SelfBalancingBinaryTree___new__, +}; + +#endif diff --git a/pydatastructs/trees/_backend/cpp/trees.cpp b/pydatastructs/trees/_backend/cpp/trees.cpp index 89699d008..bd8280da7 100644 --- a/pydatastructs/trees/_backend/cpp/trees.cpp +++ b/pydatastructs/trees/_backend/cpp/trees.cpp @@ -2,6 +2,7 @@ #include "BinaryTree.hpp" #include "BinarySearchTree.hpp" #include "BinaryTreeTraversal.hpp" +#include "SelfBalancingBinaryTree.hpp" static struct PyModuleDef trees_struct = { PyModuleDef_HEAD_INIT, @@ -33,5 +34,11 @@ PyMODINIT_FUNC PyInit__trees(void) { Py_INCREF(&BinaryTreeTraversalType); PyModule_AddObject(trees, "BinaryTreeTraversal", reinterpret_cast(&BinaryTreeTraversalType)); + if (PyType_Ready(&SelfBalancingBinaryTreeType) < 0) { + return NULL; + } + Py_INCREF(&SelfBalancingBinaryTreeType); + PyModule_AddObject(trees, "SelfBalancingBinaryTree", reinterpret_cast(&SelfBalancingBinaryTreeType)); + return trees; } diff --git a/pydatastructs/trees/binary_trees.py b/pydatastructs/trees/binary_trees.py index 27addf595..cdc778539 100644 --- a/pydatastructs/trees/binary_trees.py +++ b/pydatastructs/trees/binary_trees.py @@ -684,6 +684,15 @@ class SelfBalancingBinaryTree(BinarySearchTree): """ Represents Base class for all rotation based balancing trees like AVL tree, Red Black tree, Splay Tree. """ + def __new__(cls, key=None, root_data=None, comp=None, + is_order_statistic=False, **kwargs): + backend = kwargs.get('backend', Backend.PYTHON) + if backend == Backend.CPP: + if comp is None: + comp = lambda key1, key2: key1 < key2 + return _trees.SelfBalancingBinaryTree(key, root_data, comp, is_order_statistic, **kwargs) # If any argument is not given, then it is passed as None, except for comp + return super().__new__(cls, key, root_data, comp, is_order_statistic, **kwargs) + def _right_rotate(self, j, k): y = self.tree[k].right if y is not None: diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index fc5b98923..3b41d8254 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -436,11 +436,11 @@ def test_Treap(): assert tree.search(2) == 1 assert tree.delete(1) is None -def test_issue_234(): +def _test_SelfBalancingBinaryTree(backend): """ https://github.com/codezonediitj/pydatastructs/issues/234 """ - tree = SelfBalancingBinaryTree() + tree = SelfBalancingBinaryTree(backend=backend) tree.insert(5, 5) tree.insert(5.5, 5.5) tree.insert(4.5, 4.5) @@ -450,11 +450,13 @@ def test_issue_234(): tree.insert(4.65, 4.65) original_tree = str(tree) tree._right_rotate(3, 5) + + assert str(tree) == "[(2, 5, 5, 1), (None, 5.5, 5.5, None), (4, 4.5, 4.5, 5), (None, 4.6, 4.6, 6), (None, 4.4, 4.4, None), (None, 4.55, 4.55, 3), (None, 4.65, 4.65, None)]" assert tree.tree[3].parent == 5 assert tree.tree[2].right != 3 assert tree.tree[tree.tree[5].parent].right == 5 - trav = BinaryTreeTraversal(tree) + trav = BinaryTreeTraversal(tree, backend=backend) in_order = trav.depth_first_search(order='in_order') pre_order = trav.depth_first_search(order='pre_order') assert [node.key for node in in_order] == [4.4, 4.5, 4.55, 4.6, 4.65, 5, 5.5] @@ -467,6 +469,18 @@ def test_issue_234(): tree.insert(4.56, 4.56) tree._left_rotate(5, 8) assert tree.tree[tree.tree[8].parent].left == 8 + assert str(tree) == "[(2, 5, 5, 1), (None, 5.5, 5.5, None), (4, 4.5, 4.5, 3), (8, 4.6, 4.6, 6), (None, 4.4, 4.4, None), (7, 4.55, 4.55, None), (None, 4.65, 4.65, None), (None, 4.54, 4.54, None), (5, 4.56, 4.56, None)]" + + tree._left_right_rotate(0, 2) + assert str(tree) == "[(6, 5, 5, 1), (None, 5.5, 5.5, None), (4, 4.5, 4.5, 8), (2, 4.6, 4.6, 0), (None, 4.4, 4.4, None), (7, 4.55, 4.55, None), (None, 4.65, 4.65, None), (None, 4.54, 4.54, None), (5, 4.56, 4.56, None)]" + + tree._right_left_rotate(0, 2) + assert str(tree) == "[(6, 5, 5, None), (None, 5.5, 5.5, None), (None, 4.5, 4.5, 8), (2, 4.6, 4.6, 4), (0, 4.4, 4.4, 2), (7, 4.55, 4.55, None), (None, 4.65, 4.65, None), (None, 4.54, 4.54, None), (5, 4.56, 4.56, None)]" + +def test_SelfBalancingBinaryTree(): + _test_SelfBalancingBinaryTree(Backend.PYTHON) +def test_cpp_SelfBalancingBinaryTree(): + _test_SelfBalancingBinaryTree(Backend.CPP) def test_SplayTree(): t = SplayTree(100, 100)