From 8c5f1e79f0aa48148ee4f68c6a6427559a4b5ea6 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Tue, 4 Jun 2024 16:51:42 +0530 Subject: [PATCH 1/9] SelfBalancignBinaryTree _right_rotate() added --- .../_backend/cpp/BinaryTreeTraversal.hpp | 7 + .../_backend/cpp/SelfBalancingBinaryTree.hpp | 172 ++++++++++++++++++ pydatastructs/trees/_backend/cpp/trees.cpp | 7 + pydatastructs/trees/binary_trees.py | 9 + 4 files changed, 195 insertions(+) create mode 100644 pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp diff --git a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index a20e6b5aa..84e7b9e74 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,6 +33,12 @@ 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 (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; + } + else if (PyObject_IsInstance(tree, (PyObject *)&SelfBalancingBinaryTreeType)) { + self->tree = reinterpret_cast(tree)->bst->binary_tree; + } if (PyObject_IsInstance(tree, (PyObject *)&BinarySearchTreeType)) { self->tree = reinterpret_cast(tree)->binary_tree; } diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp new file mode 100644 index 000000000..81bb941e6 --- /dev/null +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -0,0 +1,172 @@ +#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; +} 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); + + 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 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}, + {NULL} +}; + +static PyMemberDef SelfBalancingBinaryTree_PyMemberDef[] = { + {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 \ No newline at end of file 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..d62207d41 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: From 3200acd020cd1b151b07113886300d5581c3cab5 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Tue, 4 Jun 2024 17:01:53 +0530 Subject: [PATCH 2/9] Added tree member and tests to SBBT --- .../_backend/cpp/BinaryTreeTraversal.hpp | 6 ++-- .../_backend/cpp/SelfBalancingBinaryTree.hpp | 2 ++ .../trees/tests/test_binary_trees.py | 34 ++++++++++--------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index 84e7b9e74..9e784d3cd 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp @@ -36,12 +36,12 @@ static PyObject* BinaryTreeTraversal___new__(PyTypeObject* type, PyObject *args, 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; } - else if (PyObject_IsInstance(tree, (PyObject *)&SelfBalancingBinaryTreeType)) { - self->tree = reinterpret_cast(tree)->bst->binary_tree; - } if (PyObject_IsInstance(tree, (PyObject *)&BinarySearchTreeType)) { self->tree = reinterpret_cast(tree)->binary_tree; } + else if (PyObject_IsInstance(tree, (PyObject *)&SelfBalancingBinaryTreeType)) { + self->tree = reinterpret_cast(tree)->bst->binary_tree; + } else { PyErr_SetString(PyExc_ValueError, "Not a supported type for BinaryTreeTraversal."); return NULL; diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp index 81bb941e6..25c5b83bf 100644 --- a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -14,6 +14,7 @@ typedef struct { PyObject_HEAD BinarySearchTree* bst; + ArrayForTrees* tree; } SelfBalancingBinaryTree; static void SelfBalancingBinaryTree_dealloc(SelfBalancingBinaryTree *self) { @@ -29,6 +30,7 @@ static PyObject* SelfBalancingBinaryTree___new__(PyTypeObject* type, PyObject *a } PyObject* p = BinarySearchTree___new__(&BinarySearchTreeType, args, kwds); self->bst = reinterpret_cast(p); + self->tree = reinterpret_cast(p)->binary_tree->tree; return reinterpret_cast(self); } diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index fc5b98923..16d2c768e 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(): """ https://github.com/codezonediitj/pydatastructs/issues/234 """ - tree = SelfBalancingBinaryTree() + tree = SelfBalancingBinaryTree(backend=Backend.CPP) tree.insert(5, 5) tree.insert(5.5, 5.5) tree.insert(4.5, 4.5) @@ -450,24 +450,26 @@ 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) - 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] - assert [node.key for node in pre_order] == [5, 4.5, 4.4, 4.55, 4.6, 4.65, 5.5] - - assert tree.tree[tree.tree[3].parent].right == 3 - tree._left_rotate(5, 3) - assert str(tree) == original_tree - tree.insert(4.54, 4.54) - tree.insert(4.56, 4.56) - tree._left_rotate(5, 8) - assert tree.tree[tree.tree[8].parent].left == 8 - + # trav = BinaryTreeTraversal(tree, backend=Backend.CPP) + # 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] + # assert [node.key for node in pre_order] == [5, 4.5, 4.4, 4.55, 4.6, 4.65, 5.5] + + # assert tree.tree[tree.tree[3].parent].right == 3 + # tree._left_rotate(5, 3) + # assert str(tree) == original_tree + # tree.insert(4.54, 4.54) + # tree.insert(4.56, 4.56) + # tree._left_rotate(5, 8) + # assert tree.tree[tree.tree[8].parent].left == 8 +test_SelfBalancingBinaryTree() def test_SplayTree(): t = SplayTree(100, 100) t.insert(50, 50) From 447a1cd7e8ba9b44b959eb5f9e03ef90bb9c86e3 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Tue, 4 Jun 2024 17:08:59 +0530 Subject: [PATCH 3/9] code quality --- pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp | 2 +- pydatastructs/trees/binary_trees.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp index 25c5b83bf..156b9ca50 100644 --- a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -171,4 +171,4 @@ static PyTypeObject SelfBalancingBinaryTreeType = { /* tp_new */ SelfBalancingBinaryTree___new__, }; -#endif \ No newline at end of file +#endif diff --git a/pydatastructs/trees/binary_trees.py b/pydatastructs/trees/binary_trees.py index d62207d41..cdc778539 100644 --- a/pydatastructs/trees/binary_trees.py +++ b/pydatastructs/trees/binary_trees.py @@ -692,7 +692,7 @@ def __new__(cls, key=None, root_data=None, comp=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: From 463c9aabfec32599e6a9d509c3bf8dd139928659 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Wed, 5 Jun 2024 09:31:04 +0530 Subject: [PATCH 4/9] registered tree memeber for SBBT --- pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp index 156b9ca50..92601ae67 100644 --- a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -127,6 +127,7 @@ static struct PyMethodDef SelfBalancingBinaryTree_PyMethodDef[] = { }; static PyMemberDef SelfBalancingBinaryTree_PyMemberDef[] = { + {"tree", T_OBJECT_EX, offsetof(SelfBalancingBinaryTree, tree), 0, "tree"}, {NULL} /* Sentinel */ }; From f69b9d48856cab3ba70942fbe26738b9800163f6 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Wed, 5 Jun 2024 09:40:16 +0530 Subject: [PATCH 5/9] Fixed SBBT traversal --- .../_backend/cpp/stack/ArrayStack.hpp | 1 - .../trees/_backend/cpp/BinaryTreeTraversal.hpp | 8 ++++---- pydatastructs/trees/tests/test_binary_trees.py | 12 ++++++------ 3 files changed, 10 insertions(+), 11 deletions(-) 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 9e784d3cd..5c464787c 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp @@ -36,12 +36,12 @@ static PyObject* BinaryTreeTraversal___new__(PyTypeObject* type, PyObject *args, 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 *)&BinarySearchTreeType)) { - self->tree = reinterpret_cast(tree)->binary_tree; - } - else if (PyObject_IsInstance(tree, (PyObject *)&SelfBalancingBinaryTreeType)) { + 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 { PyErr_SetString(PyExc_ValueError, "Not a supported type for BinaryTreeTraversal."); return NULL; diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 16d2c768e..830bcfd51 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -456,13 +456,13 @@ def test_SelfBalancingBinaryTree(): assert tree.tree[2].right != 3 assert tree.tree[tree.tree[5].parent].right == 5 - # trav = BinaryTreeTraversal(tree, backend=Backend.CPP) - # 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] - # assert [node.key for node in pre_order] == [5, 4.5, 4.4, 4.55, 4.6, 4.65, 5.5] + trav = BinaryTreeTraversal(tree, backend=Backend.CPP) + 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] + assert [node.key for node in pre_order] == [5, 4.5, 4.4, 4.55, 4.6, 4.65, 5.5] - # assert tree.tree[tree.tree[3].parent].right == 3 + assert tree.tree[tree.tree[3].parent].right == 3 # tree._left_rotate(5, 3) # assert str(tree) == original_tree # tree.insert(4.54, 4.54) From 57ba98e5cad538ce00c5a3114b1e186e922d9f11 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Wed, 5 Jun 2024 09:41:14 +0530 Subject: [PATCH 6/9] update --- pydatastructs/trees/tests/test_binary_trees.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 830bcfd51..6fd2a494a 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -469,7 +469,7 @@ def test_SelfBalancingBinaryTree(): # tree.insert(4.56, 4.56) # tree._left_rotate(5, 8) # assert tree.tree[tree.tree[8].parent].left == 8 -test_SelfBalancingBinaryTree() +# test_SelfBalancingBinaryTree() def test_SplayTree(): t = SplayTree(100, 100) t.insert(50, 50) From 4db9db541504e790034af3893f8bc6136cf95dec Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Wed, 5 Jun 2024 10:21:38 +0530 Subject: [PATCH 7/9] _left_rotate() in SBBT --- .../_backend/cpp/SelfBalancingBinaryTree.hpp | 30 ++++++++++++++++++- .../trees/tests/test_binary_trees.py | 26 +++++++++------- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp index 92601ae67..37870c578 100644 --- a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -88,7 +88,7 @@ static PyObject* SelfBalancingBinaryTree__right_rotate(SelfBalancingBinaryTree* 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) { + 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; @@ -110,6 +110,33 @@ static PyObject* SelfBalancingBinaryTree__right_rotate(SelfBalancingBinaryTree* 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 struct PyMethodDef SelfBalancingBinaryTree_PyMethodDef[] = { {"insert", (PyCFunction) SelfBalancingBinaryTree_insert, METH_VARARGS | METH_KEYWORDS, NULL}, {"delete", (PyCFunction) SelfBalancingBinaryTree_delete, METH_VARARGS | METH_KEYWORDS, NULL}, @@ -123,6 +150,7 @@ static struct PyMethodDef SelfBalancingBinaryTree_PyMethodDef[] = { {"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}, {NULL} }; diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 6fd2a494a..267a2c75b 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_SelfBalancingBinaryTree(): +def _test_SelfBalancingBinaryTree(backend): """ https://github.com/codezonediitj/pydatastructs/issues/234 """ - tree = SelfBalancingBinaryTree(backend=Backend.CPP) + tree = SelfBalancingBinaryTree(backend=backend) tree.insert(5, 5) tree.insert(5.5, 5.5) tree.insert(4.5, 4.5) @@ -456,20 +456,26 @@ def test_SelfBalancingBinaryTree(): assert tree.tree[2].right != 3 assert tree.tree[tree.tree[5].parent].right == 5 - trav = BinaryTreeTraversal(tree, backend=Backend.CPP) + 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] assert [node.key for node in pre_order] == [5, 4.5, 4.4, 4.55, 4.6, 4.65, 5.5] assert tree.tree[tree.tree[3].parent].right == 3 - # tree._left_rotate(5, 3) - # assert str(tree) == original_tree - # tree.insert(4.54, 4.54) - # tree.insert(4.56, 4.56) - # tree._left_rotate(5, 8) - # assert tree.tree[tree.tree[8].parent].left == 8 -# test_SelfBalancingBinaryTree() + tree._left_rotate(5, 3) + assert str(tree) == original_tree + tree.insert(4.54, 4.54) + tree.insert(4.56, 4.56) + tree._left_rotate(5, 8) + assert tree.tree[tree.tree[8].parent].left == 8 + +def test_SelfBalancingBinaryTree(): + _test_SelfBalancingBinaryTree(Backend.PYTHON) + +def test_cpp_SelfBalancingBinaryTree(): + _test_SelfBalancingBinaryTree(Backend.CPP) + def test_SplayTree(): t = SplayTree(100, 100) t.insert(50, 50) From 86e97d26f49c2ae2f9cf6165bd0e384d49b61716 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Thu, 6 Jun 2024 11:41:16 +0530 Subject: [PATCH 8/9] _left_right_rotate() for SBBT --- .../_backend/cpp/SelfBalancingBinaryTree.hpp | 42 +++++++++++++++++++ .../trees/tests/test_binary_trees.py | 5 ++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp index 37870c578..55e23cfcd 100644 --- a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -137,6 +137,47 @@ static PyObject* SelfBalancingBinaryTree__left_rotate(SelfBalancingBinaryTree* s 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 struct PyMethodDef SelfBalancingBinaryTree_PyMethodDef[] = { {"insert", (PyCFunction) SelfBalancingBinaryTree_insert, METH_VARARGS | METH_KEYWORDS, NULL}, {"delete", (PyCFunction) SelfBalancingBinaryTree_delete, METH_VARARGS | METH_KEYWORDS, NULL}, @@ -151,6 +192,7 @@ static struct PyMethodDef SelfBalancingBinaryTree_PyMethodDef[] = { {"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}, {NULL} }; diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 267a2c75b..0f82ab591 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -469,10 +469,13 @@ def _test_SelfBalancingBinaryTree(backend): 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)]" def test_SelfBalancingBinaryTree(): _test_SelfBalancingBinaryTree(Backend.PYTHON) - def test_cpp_SelfBalancingBinaryTree(): _test_SelfBalancingBinaryTree(Backend.CPP) From 9b706657e5f16fded70d8646e3cf6b9a3e6310de Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Thu, 6 Jun 2024 12:33:19 +0530 Subject: [PATCH 9/9] _right_left_rotate() for SBBT. C++ backend for SelfBalancingBinaryTree done! --- .../_backend/cpp/SelfBalancingBinaryTree.hpp | 42 +++++++++++++++++++ .../trees/tests/test_binary_trees.py | 3 ++ 2 files changed, 45 insertions(+) diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp index 55e23cfcd..f499c9bf0 100644 --- a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -178,6 +178,47 @@ static PyObject* SelfBalancingBinaryTree__left_right_rotate(SelfBalancingBinaryT 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}, @@ -193,6 +234,7 @@ static struct PyMethodDef SelfBalancingBinaryTree_PyMethodDef[] = { {"_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} }; diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 0f82ab591..3b41d8254 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -474,6 +474,9 @@ def _test_SelfBalancingBinaryTree(backend): 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():