From b21a67e7577477b70b3a79850c1120a99f809d22 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Thu, 6 Jun 2024 15:32:02 +0530 Subject: [PATCH 1/9] Created and registered RedBlackTrees, __new__() and __str__() done --- .../trees/_backend/cpp/RedBlackTree.hpp | 95 +++++++++++++++++++ .../_backend/cpp/SelfBalancingBinaryTree.hpp | 4 +- pydatastructs/trees/_backend/cpp/trees.cpp | 7 ++ pydatastructs/trees/binary_trees.py | 11 ++- 4 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 pydatastructs/trees/_backend/cpp/RedBlackTree.hpp diff --git a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp new file mode 100644 index 00000000..b14e0f8a --- /dev/null +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -0,0 +1,95 @@ +#ifndef TREES_REDBLACKTREE_HPP +#define TREES_REDBLACKTREE_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" +#include "SelfBalancingBinaryTree.hpp" + +typedef struct { + PyObject_HEAD + SelfBalancingBinaryTree* sbbt; + ArrayForTrees* tree; +} RedBlackTree; + +static void RedBlackTree_dealloc(RedBlackTree *self) { + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +static PyObject* RedBlackTree___new__(PyTypeObject* type, PyObject *args, PyObject *kwds) { + RedBlackTree *self; + self = reinterpret_cast(type->tp_alloc(type, 0)); + + 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; + } + PyObject* p = SelfBalancingBinaryTree___new__(&SelfBalancingBinaryTreeType, args, kwds); + self->sbbt = reinterpret_cast(p); + self->tree = reinterpret_cast(p)->bst->binary_tree->tree; + + return reinterpret_cast(self); +} + +static PyObject* RedBlackTree___str__(RedBlackTree *self) { + return BinarySearchTree___str__(self->sbbt->bst); +} + + + +static struct PyMethodDef RedBlackTree_PyMethodDef[] = { + {NULL} +}; + +static PyMemberDef RedBlackTree_PyMemberDef[] = { + {"tree", T_OBJECT_EX, offsetof(RedBlackTree, tree), 0, "tree"}, + {NULL} /* Sentinel */ +}; + + +static PyTypeObject RedBlackTreeType = { + /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "RedBlackTree", + /* tp_basicsize */ sizeof(RedBlackTree), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor) RedBlackTree_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) RedBlackTree___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 */ RedBlackTree_PyMethodDef, + /* tp_members */ RedBlackTree_PyMemberDef, + /* tp_getset */ 0, + /* tp_base */ &SelfBalancingBinaryTreeType, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ RedBlackTree___new__, +}; + +#endif diff --git a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp index f499c9bf..7e91d1a5 100644 --- a/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/SelfBalancingBinaryTree.hpp @@ -1,5 +1,5 @@ -#ifndef TREES_SELFBALANCINGSelfBalancingBinaryTree_HPP -#define TREES_SELFBALANCINGSelfBalancingBinaryTree_HPP +#ifndef TREES_SELFBALANCINGBINARYTREE_HPP +#define TREES_SELFBALANCINGBINARYTREE_HPP #define PY_SSIZE_T_CLEAN #include diff --git a/pydatastructs/trees/_backend/cpp/trees.cpp b/pydatastructs/trees/_backend/cpp/trees.cpp index bd8280da..a48113f4 100644 --- a/pydatastructs/trees/_backend/cpp/trees.cpp +++ b/pydatastructs/trees/_backend/cpp/trees.cpp @@ -3,6 +3,7 @@ #include "BinarySearchTree.hpp" #include "BinaryTreeTraversal.hpp" #include "SelfBalancingBinaryTree.hpp" +#include "RedBlackTree.hpp" static struct PyModuleDef trees_struct = { PyModuleDef_HEAD_INIT, @@ -40,5 +41,11 @@ PyMODINIT_FUNC PyInit__trees(void) { Py_INCREF(&SelfBalancingBinaryTreeType); PyModule_AddObject(trees, "SelfBalancingBinaryTree", reinterpret_cast(&SelfBalancingBinaryTreeType)); + if (PyType_Ready(&RedBlackTreeType) < 0) { + return NULL; + } + Py_INCREF(&RedBlackTreeType); + PyModule_AddObject(trees, "RedBlackTree", reinterpret_cast(&RedBlackTreeType)); + return trees; } diff --git a/pydatastructs/trees/binary_trees.py b/pydatastructs/trees/binary_trees.py index cdc77853..54bb7be5 100644 --- a/pydatastructs/trees/binary_trees.py +++ b/pydatastructs/trees/binary_trees.py @@ -1199,9 +1199,18 @@ class RedBlackTree(SelfBalancingBinaryTree): pydatastructs.trees.binary_trees.SelfBalancingBinaryTree """ + 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.RedBlackTree(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) + @classmethod def methods(cls): - return ['insert', 'delete'] + return ['__new__', 'insert', 'delete'] def _get_parent(self, node_idx): return self.tree[node_idx].parent From ac88b3d48b4763c7dd555a7befc290fb745272ea Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Fri, 7 Jun 2024 16:35:14 +0530 Subject: [PATCH 2/9] RedBlackTree methods till insert() --- .../trees/_backend/cpp/BinarySearchTree.hpp | 2 +- .../trees/_backend/cpp/RedBlackTree.hpp | 147 +++++++ .../trees/tests/test_binary_trees.py | 385 +++++++++--------- pydatastructs/utils/_backend/cpp/TreeNode.hpp | 3 + 4 files changed, 345 insertions(+), 192 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp b/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp index 0a920db8..482a0330 100644 --- a/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp +++ b/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp @@ -135,7 +135,7 @@ static PyObject* BinarySearchTree_insert(BinarySearchTree* self, PyObject* args) PyObject* key = Py_None; Py_INCREF(Py_None); PyObject* data = Py_None; - if (!PyArg_ParseTuple(args, "O|O", &key, &data)) { // ret_parent is optional + if (!PyArg_ParseTuple(args, "O|O", &key, &data)) { // data is optional return NULL; } diff --git a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp index b14e0f8a..6ac96427 100644 --- a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "../../../utils/_backend/cpp/utils.hpp" #include "../../../utils/_backend/cpp/TreeNode.hpp" #include "../../../linear_data_structures/_backend/cpp/arrays/ArrayForTrees.hpp" @@ -40,9 +41,155 @@ static PyObject* RedBlackTree___str__(RedBlackTree *self) { return BinarySearchTree___str__(self->sbbt->bst); } +static PyObject* RedBlackTree__get_parent(RedBlackTree *self, PyObject* args) { + long node_idx = PyLong_AsLong(PyObject_GetItem(args, PyZero)); + BinaryTree* bt = self->sbbt->bst->binary_tree; + PyObject* parent = reinterpret_cast(bt->tree->_one_dimensional_array->_data[node_idx])->parent; + return parent; +} + +static PyObject* RedBlackTree__get_grand_parent(RedBlackTree *self, PyObject* args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + PyObject* parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + + BinaryTree* bt = self->sbbt->bst->binary_tree; + PyObject* grand_parent = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->parent; + return grand_parent; +} + +static PyObject* RedBlackTree__get_sibling(RedBlackTree *self, PyObject* args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + PyObject* parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + + if (parent_idx == Py_None) { + Py_RETURN_NONE; + } + + BinaryTree* bt = self->sbbt->bst->binary_tree; + TreeNode* node = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)]); + if (node_idx == node->left) { + PyObject* sibling_idx = node->right; + return sibling_idx; + } + else { + PyObject* sibling_idx = node->left; + return sibling_idx; + } + + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree__get_uncle(RedBlackTree *self, PyObject* args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + PyObject* parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + + PyObject* uncle = RedBlackTree__get_sibling(self, Py_BuildValue("(O)", parent_idx)); + return uncle; +} + +static PyObject* RedBlackTree__is_onleft(RedBlackTree *self, PyObject* args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + PyObject* parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + + BinaryTree* bt = self->sbbt->bst->binary_tree; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->left == node_idx) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} +static PyObject* RedBlackTree__is_onright(RedBlackTree *self, PyObject* args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", node_idx)) == Py_False) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject* RedBlackTree___fix_insert(RedBlackTree *self, PyObject* args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + while (RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)) != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)))])->color == 1 && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->color == 1) { + PyObject* parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + PyObject* grand_parent_idx = RedBlackTree__get_grand_parent(self, Py_BuildValue("(O)", node_idx)); + PyObject* uncle_idx = RedBlackTree__get_uncle(self, Py_BuildValue("(O)", node_idx)); + + if(uncle_idx != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(uncle_idx)])->color == 1) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(uncle_idx)])->color = 0; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->color = 0; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(grand_parent_idx)])->color = 1; + node_idx = grand_parent_idx; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->is_root = false; + if (RedBlackTree__is_onright(self, Py_BuildValue("(O)", parent_idx)) == Py_True) { + if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", parent_idx, node_idx)); + node_idx = parent_idx; + parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + } + node_idx = parent_idx; + parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", parent_idx, node_idx)); + } + else if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", parent_idx)) == Py_True) { + if (RedBlackTree__is_onright(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", parent_idx, node_idx)); + node_idx = parent_idx; + parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + } + node_idx = parent_idx; + parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", parent_idx, node_idx)); + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->color = 0; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->color = 1; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->is_root = true; + } + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->is_root) { + break; + } + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->color = 0; + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree_insert(RedBlackTree *self, PyObject* args) { + Py_INCREF(Py_None); + PyObject* key = Py_None; + Py_INCREF(Py_None); + PyObject* data = Py_None; + if (!PyArg_ParseTuple(args, "O|O", &key, &data)) { // data is optional + return NULL; + } + SelfBalancingBinaryTree_insert(self->sbbt, Py_BuildValue("(OO)", key, data)); + PyObject* node_idx = SelfBalancingBinaryTree_search(self->sbbt, Py_BuildValue("(O)", key), PyDict_New()); + + BinaryTree* bt = self->sbbt->bst->binary_tree; + TreeNode* node = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)]); + + if (PyType_Ready(&TreeNodeType) < 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; + } + TreeNode* new_node = reinterpret_cast(TreeNode___new__(&TreeNodeType, Py_BuildValue("(OO)", key, data), PyDict_New())); + new_node->parent = node->parent; + new_node->left = node->left; + new_node->right = node->right; + bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)] = reinterpret_cast(new_node); + + if (node->is_root) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->is_root = true; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->color = 0; + } + else if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->parent)])->color == 1) { + RedBlackTree___fix_insert(self, Py_BuildValue("(O)", node_idx)); + } + + Py_RETURN_NONE; +} static struct PyMethodDef RedBlackTree_PyMethodDef[] = { + {"insert", (PyCFunction) RedBlackTree_insert, METH_VARARGS, NULL}, {NULL} }; diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 3b41d825..442e450e 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -543,7 +543,8 @@ def test_SplayTree(): assert [node.key for node in pre_order] == [200, 55, 50, 30, 20, 100] def test_RedBlackTree(): - tree = RedBlackTree() + tree = RedBlackTree(backend=Backend.CPP) + # tree = RedBlackTree() tree.insert(10, 10) tree.insert(18, 18) tree.insert(7, 7) @@ -556,193 +557,195 @@ def test_RedBlackTree(): tree.insert(2, 2) tree.insert(17, 17) tree.insert(6, 6) - - 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] == [2, 6, 7, 10, 15, 16, 17, 18, 25, 30, 40, 60] - assert [node.key for node in pre_order] == [16, 10, 6, 2, 7, 15, 25, 18, 17, 40, 30, 60] - - assert tree.lower_bound(0) == 2 - assert tree.lower_bound(2) == 2 - assert tree.lower_bound(3) == 6 - assert tree.lower_bound(7) == 7 - assert tree.lower_bound(25) == 25 - assert tree.lower_bound(32) == 40 - assert tree.lower_bound(41) == 60 - assert tree.lower_bound(60) == 60 - assert tree.lower_bound(61) is None - - assert tree.upper_bound(0) == 2 - assert tree.upper_bound(2) == 6 - assert tree.upper_bound(3) == 6 - assert tree.upper_bound(7) == 10 - assert tree.upper_bound(25) == 30 - assert tree.upper_bound(32) == 40 - assert tree.upper_bound(41) == 60 - assert tree.upper_bound(60) is None - assert tree.upper_bound(61) is None - - tree = RedBlackTree() - - assert tree.lower_bound(1) is None - assert tree.upper_bound(0) is None - - tree.insert(10) - tree.insert(20) - tree.insert(30) - tree.insert(40) - tree.insert(50) - tree.insert(60) - tree.insert(70) - tree.insert(80) - tree.insert(90) - tree.insert(100) - tree.insert(110) - tree.insert(120) - tree.insert(130) - tree.insert(140) - tree.insert(150) - tree.insert(160) - tree.insert(170) - tree.insert(180) - - assert tree._get_sibling(7) is None - - 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, - 100, 110, 120, 130, 140, 150, 160, 170, 180] - assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, - 90, 110, 140, 130, 160, 150, 170, 180] - - tree.delete(180) - tree.delete(130) - tree.delete(110) - tree.delete(190) - 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, - 120, 140, 150, 160, 170] - assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, - 90, 160, 140, 150, 170] - - tree.delete(170) - tree.delete(100) - tree.delete(60) - 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] == [10, 20, 30, 40, 50, 70, 80, 90, 120, 140, 150, 160] - assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 70, 120, 90, 150, 140, 160] - - tree.delete(70) - tree.delete(140) - - 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] == [10, 20, 30, 40, 50, 80, 90, 120, 150, 160] - assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 120, 90, 150, 160] - - tree.delete(150) - tree.delete(120) - 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] == [10, 20, 30, 40, 50, 80, 90, 160] - assert [node.key for node in pre_order] == [40, 20, 10, 30, 80, 50, 90, 160] - - tree.delete(50) - tree.delete(80) - 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] == [10, 20, 30, 40, 90, 160] - assert [node.key for node in pre_order] == [40, 20, 10, 30, 90, 160] - - tree.delete(30) - tree.delete(20) - 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] == [10, 40, 90, 160] - assert [node.key for node in pre_order] == [40, 10, 90, 160] - - tree.delete(10) - 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] == [40, 90, 160] - assert [node.key for node in pre_order] == [90, 40, 160] - - tree.delete(40) - tree.delete(90) - 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] == [160] - assert [node.key for node in pre_order] == [160] - - tree.delete(160) - 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 if node.key is not None] == [] - assert [node.key for node in pre_order if node.key is not None] == [] - - tree = RedBlackTree() - tree.insert(50) - tree.insert(40) - tree.insert(30) - tree.insert(20) - tree.insert(10) - tree.insert(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] == [5, 10, 20, 30, 40, 50] - assert [node.key for node in pre_order] == [40, 20, 10, 5, 30, 50] - - tree.delete(50) - tree.delete(20) - tree.delete(30) - - 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] == [5, 10, 40] - assert [node.key for node in pre_order] == [10, 5, 40] - - tree = RedBlackTree() - tree.insert(10) - tree.insert(5) - tree.insert(20) - tree.insert(15) - - 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] == [5, 10, 15, 20] - assert [node.key for node in pre_order] == [10, 5, 20, 15] - - tree.delete(5) - - 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] == [10, 15, 20] - assert [node.key for node in pre_order] == [15, 10, 20] - - tree = RedBlackTree() - tree.insert(10) - tree.insert(5) - tree.insert(20) - tree.insert(15) - tree.insert(2) - tree.insert(6) - - 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] == [2, 5, 6, 10, 15, 20] - assert [node.key for node in pre_order] == [10, 5, 2, 6, 20, 15] - - tree.delete(10) - - 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] == [2, 5, 6, 15, 20] - assert [node.key for node in pre_order] == [6, 5, 2, 20, 15] + assert str(tree) == "[(11, 10, 10, 3), (10, 18, 18, None), (None, 7, 7, None), (None, 15, 15, None), (0, 16, 16, 6), (None, 30, 30, None), (1, 25, 25, 7), (5, 40, 40, 8), (None, 60, 60, None), (None, 2, 2, None), (None, 17, 17, None), (9, 6, 6, 2)]" + + # 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] == [2, 6, 7, 10, 15, 16, 17, 18, 25, 30, 40, 60] + # assert [node.key for node in pre_order] == [16, 10, 6, 2, 7, 15, 25, 18, 17, 40, 30, 60] + + # assert tree.lower_bound(0) == 2 + # assert tree.lower_bound(2) == 2 + # assert tree.lower_bound(3) == 6 + # assert tree.lower_bound(7) == 7 + # assert tree.lower_bound(25) == 25 + # assert tree.lower_bound(32) == 40 + # assert tree.lower_bound(41) == 60 + # assert tree.lower_bound(60) == 60 + # assert tree.lower_bound(61) is None + + # assert tree.upper_bound(0) == 2 + # assert tree.upper_bound(2) == 6 + # assert tree.upper_bound(3) == 6 + # assert tree.upper_bound(7) == 10 + # assert tree.upper_bound(25) == 30 + # assert tree.upper_bound(32) == 40 + # assert tree.upper_bound(41) == 60 + # assert tree.upper_bound(60) is None + # assert tree.upper_bound(61) is None + + # tree = RedBlackTree() + + # assert tree.lower_bound(1) is None + # assert tree.upper_bound(0) is None + + # tree.insert(10) + # tree.insert(20) + # tree.insert(30) + # tree.insert(40) + # tree.insert(50) + # tree.insert(60) + # tree.insert(70) + # tree.insert(80) + # tree.insert(90) + # tree.insert(100) + # tree.insert(110) + # tree.insert(120) + # tree.insert(130) + # tree.insert(140) + # tree.insert(150) + # tree.insert(160) + # tree.insert(170) + # tree.insert(180) + + # assert tree._get_sibling(7) is None + + # 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, + # 100, 110, 120, 130, 140, 150, 160, 170, 180] + # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, + # 90, 110, 140, 130, 160, 150, 170, 180] + + # tree.delete(180) + # tree.delete(130) + # tree.delete(110) + # tree.delete(190) + # 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, + # 120, 140, 150, 160, 170] + # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, + # 90, 160, 140, 150, 170] + + # tree.delete(170) + # tree.delete(100) + # tree.delete(60) + # 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] == [10, 20, 30, 40, 50, 70, 80, 90, 120, 140, 150, 160] + # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 70, 120, 90, 150, 140, 160] + + # tree.delete(70) + # tree.delete(140) + + # 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] == [10, 20, 30, 40, 50, 80, 90, 120, 150, 160] + # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 120, 90, 150, 160] + + # tree.delete(150) + # tree.delete(120) + # 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] == [10, 20, 30, 40, 50, 80, 90, 160] + # assert [node.key for node in pre_order] == [40, 20, 10, 30, 80, 50, 90, 160] + + # tree.delete(50) + # tree.delete(80) + # 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] == [10, 20, 30, 40, 90, 160] + # assert [node.key for node in pre_order] == [40, 20, 10, 30, 90, 160] + + # tree.delete(30) + # tree.delete(20) + # 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] == [10, 40, 90, 160] + # assert [node.key for node in pre_order] == [40, 10, 90, 160] + + # tree.delete(10) + # 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] == [40, 90, 160] + # assert [node.key for node in pre_order] == [90, 40, 160] + + # tree.delete(40) + # tree.delete(90) + # 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] == [160] + # assert [node.key for node in pre_order] == [160] + + # tree.delete(160) + # 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 if node.key is not None] == [] + # assert [node.key for node in pre_order if node.key is not None] == [] + + # tree = RedBlackTree() + # tree.insert(50) + # tree.insert(40) + # tree.insert(30) + # tree.insert(20) + # tree.insert(10) + # tree.insert(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] == [5, 10, 20, 30, 40, 50] + # assert [node.key for node in pre_order] == [40, 20, 10, 5, 30, 50] + + # tree.delete(50) + # tree.delete(20) + # tree.delete(30) + + # 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] == [5, 10, 40] + # assert [node.key for node in pre_order] == [10, 5, 40] + + # tree = RedBlackTree() + # tree.insert(10) + # tree.insert(5) + # tree.insert(20) + # tree.insert(15) + + # 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] == [5, 10, 15, 20] + # assert [node.key for node in pre_order] == [10, 5, 20, 15] + + # tree.delete(5) + + # 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] == [10, 15, 20] + # assert [node.key for node in pre_order] == [15, 10, 20] + + # tree = RedBlackTree() + # tree.insert(10) + # tree.insert(5) + # tree.insert(20) + # tree.insert(15) + # tree.insert(2) + # tree.insert(6) + + # 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] == [2, 5, 6, 10, 15, 20] + # assert [node.key for node in pre_order] == [10, 5, 2, 6, 20, 15] + + # tree.delete(10) + + # 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] == [2, 5, 6, 15, 20] + # assert [node.key for node in pre_order] == [6, 5, 2, 20, 15] +test_RedBlackTree() diff --git a/pydatastructs/utils/_backend/cpp/TreeNode.hpp b/pydatastructs/utils/_backend/cpp/TreeNode.hpp index 41c64f72..e7ed2841 100644 --- a/pydatastructs/utils/_backend/cpp/TreeNode.hpp +++ b/pydatastructs/utils/_backend/cpp/TreeNode.hpp @@ -17,6 +17,7 @@ typedef struct { long height; PyObject* parent; long size; + long color; } TreeNode; static void TreeNode_dealloc(TreeNode *self) { @@ -40,6 +41,7 @@ static PyObject* TreeNode___new__(PyTypeObject* type, PyObject *args, PyObject * self->height = 0; self->size = 1; self->is_root = false; + self->color = 1; return reinterpret_cast(self); } @@ -59,6 +61,7 @@ static struct PyMemberDef TreeNode_PyMemberDef[] = { {"left", T_OBJECT, offsetof(TreeNode, left), 0, "TreeNode left"}, {"right", T_OBJECT, offsetof(TreeNode, right), 0, "TreeNode right"}, {"parent", T_OBJECT, offsetof(TreeNode, parent), 0, "TreeNode parent"}, + {"color", T_LONG, offsetof(TreeNode, size), 0, "RedBlackTreeNode color"}, {NULL}, }; From bc02f342e72d37acfabe7715a79386e6300f66f0 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Fri, 7 Jun 2024 16:41:17 +0530 Subject: [PATCH 3/9] All RedBlackTree traversals done --- .../trees/_backend/cpp/BinaryTreeTraversal.hpp | 10 +++++++++- pydatastructs/trees/tests/test_binary_trees.py | 10 +++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index 5c464787..c85d6b12 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp @@ -14,6 +14,7 @@ #include "BinaryTree.hpp" #include "BinarySearchTree.hpp" #include "SelfBalancingBinaryTree.hpp" +#include "RedBlackTree.hpp" typedef struct { PyObject_HEAD @@ -36,7 +37,14 @@ 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 *)&SelfBalancingBinaryTreeType)) { + if (PyType_Ready(&RedBlackTreeType) < 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 *)&RedBlackTreeType)) { + self->tree = reinterpret_cast(tree)->sbbt->bst->binary_tree; + } + else if (PyObject_IsInstance(tree, (PyObject *)&SelfBalancingBinaryTreeType)) { self->tree = reinterpret_cast(tree)->bst->binary_tree; } else if (PyObject_IsInstance(tree, (PyObject *)&BinarySearchTreeType)) { diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 442e450e..a77a7175 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -559,11 +559,11 @@ def test_RedBlackTree(): tree.insert(6, 6) assert str(tree) == "[(11, 10, 10, 3), (10, 18, 18, None), (None, 7, 7, None), (None, 15, 15, None), (0, 16, 16, 6), (None, 30, 30, None), (1, 25, 25, 7), (5, 40, 40, 8), (None, 60, 60, None), (None, 2, 2, None), (None, 17, 17, None), (9, 6, 6, 2)]" - # 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] == [2, 6, 7, 10, 15, 16, 17, 18, 25, 30, 40, 60] - # assert [node.key for node in pre_order] == [16, 10, 6, 2, 7, 15, 25, 18, 17, 40, 30, 60] + 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] == [2, 6, 7, 10, 15, 16, 17, 18, 25, 30, 40, 60] + assert [node.key for node in pre_order] == [16, 10, 6, 2, 7, 15, 25, 18, 17, 40, 30, 60] # assert tree.lower_bound(0) == 2 # assert tree.lower_bound(2) == 2 From a5915498a3982cb263568e828697cc111ad09ea7 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Fri, 7 Jun 2024 16:47:26 +0530 Subject: [PATCH 4/9] lower_bound() and upper_bound() --- .../trees/_backend/cpp/RedBlackTree.hpp | 10 +++++ .../trees/tests/test_binary_trees.py | 38 +++++++++---------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp index 6ac96427..da171d1f 100644 --- a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -188,8 +188,18 @@ static PyObject* RedBlackTree_insert(RedBlackTree *self, PyObject* args) { Py_RETURN_NONE; } +static PyObject* RedBlackTree_lower_bound(RedBlackTree* self, PyObject *args, PyObject *kwds) { + return BinarySearchTree_lower_bound(self->sbbt->bst, args, kwds); +} + +static PyObject* RedBlackTree_upper_bound(RedBlackTree* self, PyObject *args, PyObject *kwds) { + return BinarySearchTree_upper_bound(self->sbbt->bst, args, kwds); +} + static struct PyMethodDef RedBlackTree_PyMethodDef[] = { {"insert", (PyCFunction) RedBlackTree_insert, METH_VARARGS, NULL}, + {"lower_bound", (PyCFunction) RedBlackTree_lower_bound, METH_VARARGS | METH_KEYWORDS, NULL}, + {"upper_bound", (PyCFunction) RedBlackTree_upper_bound, METH_VARARGS | METH_KEYWORDS, NULL}, {NULL} }; diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index a77a7175..5ed42da6 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -565,25 +565,25 @@ def test_RedBlackTree(): assert [node.key for node in in_order] == [2, 6, 7, 10, 15, 16, 17, 18, 25, 30, 40, 60] assert [node.key for node in pre_order] == [16, 10, 6, 2, 7, 15, 25, 18, 17, 40, 30, 60] - # assert tree.lower_bound(0) == 2 - # assert tree.lower_bound(2) == 2 - # assert tree.lower_bound(3) == 6 - # assert tree.lower_bound(7) == 7 - # assert tree.lower_bound(25) == 25 - # assert tree.lower_bound(32) == 40 - # assert tree.lower_bound(41) == 60 - # assert tree.lower_bound(60) == 60 - # assert tree.lower_bound(61) is None - - # assert tree.upper_bound(0) == 2 - # assert tree.upper_bound(2) == 6 - # assert tree.upper_bound(3) == 6 - # assert tree.upper_bound(7) == 10 - # assert tree.upper_bound(25) == 30 - # assert tree.upper_bound(32) == 40 - # assert tree.upper_bound(41) == 60 - # assert tree.upper_bound(60) is None - # assert tree.upper_bound(61) is None + assert tree.lower_bound(0) == 2 + assert tree.lower_bound(2) == 2 + assert tree.lower_bound(3) == 6 + assert tree.lower_bound(7) == 7 + assert tree.lower_bound(25) == 25 + assert tree.lower_bound(32) == 40 + assert tree.lower_bound(41) == 60 + assert tree.lower_bound(60) == 60 + assert tree.lower_bound(61) is None + + assert tree.upper_bound(0) == 2 + assert tree.upper_bound(2) == 6 + assert tree.upper_bound(3) == 6 + assert tree.upper_bound(7) == 10 + assert tree.upper_bound(25) == 30 + assert tree.upper_bound(32) == 40 + assert tree.upper_bound(41) == 60 + assert tree.upper_bound(60) is None + assert tree.upper_bound(61) is None # tree = RedBlackTree() From e8d22904f3f9f951a10a3740f26ec813a3f2b80c Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Fri, 7 Jun 2024 16:54:00 +0530 Subject: [PATCH 5/9] registered RedBlackTree methods --- .../trees/_backend/cpp/RedBlackTree.hpp | 4 ++ .../trees/tests/test_binary_trees.py | 64 +++++++++---------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp index da171d1f..c58f8082 100644 --- a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -200,6 +200,10 @@ static struct PyMethodDef RedBlackTree_PyMethodDef[] = { {"insert", (PyCFunction) RedBlackTree_insert, METH_VARARGS, NULL}, {"lower_bound", (PyCFunction) RedBlackTree_lower_bound, METH_VARARGS | METH_KEYWORDS, NULL}, {"upper_bound", (PyCFunction) RedBlackTree_upper_bound, METH_VARARGS | METH_KEYWORDS, NULL}, + {"_get_parent", (PyCFunction) RedBlackTree__get_parent, METH_VARARGS, NULL}, + {"_get_grand_parent", (PyCFunction) RedBlackTree__get_grand_parent, METH_VARARGS, NULL}, + {"_get_sibling", (PyCFunction) RedBlackTree__get_sibling, METH_VARARGS, NULL}, + {"_get_uncle", (PyCFunction) RedBlackTree__get_uncle, METH_VARARGS, NULL}, {NULL} }; diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 5ed42da6..13dc8232 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -544,7 +544,6 @@ def test_SplayTree(): def test_RedBlackTree(): tree = RedBlackTree(backend=Backend.CPP) - # tree = RedBlackTree() tree.insert(10, 10) tree.insert(18, 18) tree.insert(7, 7) @@ -585,39 +584,40 @@ def test_RedBlackTree(): assert tree.upper_bound(60) is None assert tree.upper_bound(61) is None - # tree = RedBlackTree() - - # assert tree.lower_bound(1) is None - # assert tree.upper_bound(0) is None + tree = RedBlackTree(backend=Backend.CPP) - # tree.insert(10) - # tree.insert(20) - # tree.insert(30) - # tree.insert(40) - # tree.insert(50) - # tree.insert(60) - # tree.insert(70) - # tree.insert(80) - # tree.insert(90) - # tree.insert(100) - # tree.insert(110) - # tree.insert(120) - # tree.insert(130) - # tree.insert(140) - # tree.insert(150) - # tree.insert(160) - # tree.insert(170) - # tree.insert(180) - - # assert tree._get_sibling(7) is None + assert tree.lower_bound(1) is None + assert tree.upper_bound(0) is None + + tree.insert(10) + tree.insert(20) + tree.insert(30) + tree.insert(40) + tree.insert(50) + tree.insert(60) + tree.insert(70) + tree.insert(80) + tree.insert(90) + tree.insert(100) + tree.insert(110) + tree.insert(120) + tree.insert(130) + tree.insert(140) + tree.insert(150) + tree.insert(160) + tree.insert(170) + tree.insert(180) + assert str(tree) == "[(None, 10, None, None), (0, 20, None, 2), (None, 30, None, None), (1, 40, None, 5), (None, 50, None, None), (4, 60, None, 6), (None, 70, None, None), (3, 80, None, 11), (None, 90, None, None), (8, 100, None, 10), (None, 110, None, None), (9, 120, None, 13), (None, 130, None, None), (12, 140, None, 15), (None, 150, None, None), (14, 160, None, 16), (None, 170, None, 17), (None, 180, None, None)]" + + assert tree._get_sibling(7) is None - # 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, - # 100, 110, 120, 130, 140, 150, 160, 170, 180] - # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, - # 90, 110, 140, 130, 160, 150, 170, 180] + 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, + 100, 110, 120, 130, 140, 150, 160, 170, 180] + assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, + 90, 110, 140, 130, 160, 150, 170, 180] # tree.delete(180) # tree.delete(130) From 216a9deb7a2bbab39e79df7132fa7439dbc42571 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Tue, 11 Jun 2024 16:14:02 +0530 Subject: [PATCH 6/9] C++ backend for Red Black Trees done --- .../trees/_backend/cpp/RedBlackTree.hpp | 384 +++++++++++++++++- .../trees/tests/test_binary_trees.py | 275 +++++++------ 2 files changed, 522 insertions(+), 137 deletions(-) diff --git a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp index c58f8082..d87afaaf 100644 --- a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include "../../../utils/_backend/cpp/utils.hpp" #include "../../../utils/_backend/cpp/TreeNode.hpp" #include "../../../linear_data_structures/_backend/cpp/arrays/ArrayForTrees.hpp" @@ -114,7 +113,7 @@ static PyObject* RedBlackTree___fix_insert(RedBlackTree *self, PyObject* args) { PyObject* grand_parent_idx = RedBlackTree__get_grand_parent(self, Py_BuildValue("(O)", node_idx)); PyObject* uncle_idx = RedBlackTree__get_uncle(self, Py_BuildValue("(O)", node_idx)); - if(uncle_idx != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(uncle_idx)])->color == 1) { + if (uncle_idx != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(uncle_idx)])->color == 1) { reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(uncle_idx)])->color = 0; reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->color = 0; reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(grand_parent_idx)])->color = 1; @@ -196,8 +195,389 @@ static PyObject* RedBlackTree_upper_bound(RedBlackTree* self, PyObject *args, Py return BinarySearchTree_upper_bound(self->sbbt->bst, args, kwds); } +static PyObject* RedBlackTree__find_predecessor(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + while (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right != Py_None) { + node_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right; + } + return node_idx; +} + +static PyObject* RedBlackTree__is_leaf(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left == Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right == Py_None) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject* RedBlackTree__has_two_child(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right != Py_None) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject* RedBlackTree__has_one_child(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + if (RedBlackTree__is_leaf(self, Py_BuildValue("(O)", node_idx)) == Py_False && RedBlackTree__has_two_child(self, Py_BuildValue("(O)", node_idx)) == Py_False) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject* RedBlackTree__transplant_values(RedBlackTree* self, PyObject *args) { + PyObject* node_idx1 = PyObject_GetItem(args, PyZero); + PyObject* node_idx2 = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* parent = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx1)])->parent; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx1)])->is_root == true && RedBlackTree__has_one_child(self, Py_BuildValue("(O)", node_idx1)) == Py_True) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->key = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx2)])->key; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->data = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx2)])->data; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->left = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx2)])->left; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->right = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx2)])->right; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx1)])->parent == Py_None; + + return reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->key; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx1)])->key = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx2)])->key; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx1)])->data = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx2)])->data; + } + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___has_red_child(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + PyObject* left_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left; + PyObject* right_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right; + if ((left_idx != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(left_idx)])->color == 1) || (right_idx != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(right_idx)])->color == 1)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject* RedBlackTree__replace_node(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + if (RedBlackTree__is_leaf(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + Py_RETURN_NONE; + } + else if (RedBlackTree__has_one_child(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + BinaryTree* bt = self->sbbt->bst->binary_tree; + PyObject* child; + + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left != Py_None) { + child = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left; + } + else { + child = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right; + } + return child; + } + else { + BinaryTree* bt = self->sbbt->bst->binary_tree; + PyObject* node = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left; + return RedBlackTree__find_predecessor(self, Py_BuildValue("(O)", node)); + } + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___walk1_walk_isblack(RedBlackTree* self, PyObject *args) { + PyObject* color = PyObject_GetItem(args, PyZero); + PyObject* node_idx1 = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + if ((node_idx1 == Py_None || reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx1)])->color == 0) && (color == PyZero)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; +} + +static PyObject* RedBlackTree___left_left_sublingcase(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* left_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left; + PyObject* parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + long parent_color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->color; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(left_idx)])->color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->color; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->color = parent_color; + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", parent, node_idx)); + + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___right_left_sublingcase(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* left_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->left; + PyObject* parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + long parent_color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->color; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(left_idx)])->color = parent_color; + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", node_idx, left_idx)); + PyObject* child = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", parent, child)); + + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___left_right_sublingcase(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* right_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right; + PyObject* parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + long parent_color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->color; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(right_idx)])->color = parent_color; + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", node_idx, right_idx)); + PyObject* child = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", parent, child)); + + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___right_right_sublingcase(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* right_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->right; + PyObject* parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + long parent_color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->color; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(right_idx)])->color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->color; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->color = parent_color; + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", parent, node_idx)); + + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___fix_deletion(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + TreeNode* node = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)]); + long color = node->color; + while (node_idx != bt->root_idx && color == 0) { + PyObject* sibling_idx = RedBlackTree__get_sibling(self, Py_BuildValue("(O)", node_idx)); + PyObject* parent_idx = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + if (sibling_idx == Py_None) { + node_idx = parent_idx; + continue; + } + else { + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(sibling_idx)])->color == 1) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->is_root = false; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->color = 1; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(sibling_idx)])->color = 0; + if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", sibling_idx)) == Py_True) { + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", parent_idx, sibling_idx)); + } + else { + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", parent_idx, sibling_idx)); + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->is_root = true; + continue; + } + else { + if (RedBlackTree___has_red_child(self, Py_BuildValue("(O)", sibling_idx)) == Py_True) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->is_root = false; + PyObject* left_idx = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(sibling_idx)])->left; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(sibling_idx)])->left != Py_None && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(left_idx)])->color == 1) { + if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", sibling_idx)) == Py_True) { + RedBlackTree___left_left_sublingcase(self, Py_BuildValue("(O)", sibling_idx)); + } + else { + RedBlackTree___right_left_sublingcase(self, Py_BuildValue("(O)", sibling_idx)); + } + } + else { + if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", sibling_idx)) == Py_True) { + RedBlackTree___left_right_sublingcase(self, Py_BuildValue("(O)", sibling_idx)); + } + else { + RedBlackTree___right_right_sublingcase(self, Py_BuildValue("(O)", sibling_idx)); + } + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->is_root = true; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->color = 0; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(sibling_idx)])->color = 1; + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->color == 0) { + node_idx = parent_idx; + continue; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent_idx)])->color = 0; + } + } + } + } + color = 1; + } + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree__remove_node(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + PyObject* a = parent; + if (RedBlackTree__is_leaf(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + PyObject* par_key = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->key; + PyObject* root_key = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->key; + PyObject* new_indices = ArrayForTrees_delete(bt->tree, Py_BuildValue("(O)", node_idx)); + if (new_indices != Py_None) { + a = PyDict_GetItem(new_indices, par_key); + bt->root_idx = PyDict_GetItem(new_indices, root_key); + } + } + else if (RedBlackTree__has_one_child(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + PyObject* child = RedBlackTree__replace_node(self, Py_BuildValue("(O)", node_idx)); + parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + PyObject* par_key = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->key; + PyObject* root_key = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->key; + PyObject* new_indices = ArrayForTrees_delete(bt->tree, Py_BuildValue("(O)", node_idx)); + } + BinarySearchTree__update_size(self->sbbt->bst, Py_BuildValue("(O)", a)); + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree__delete_root(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + PyObject* node_idx1 = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + if (RedBlackTree__is_leaf(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->data = Py_None; + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->key = Py_None; + } + else if (RedBlackTree__has_one_child(self, Py_BuildValue("(O)", node_idx)) == Py_True) { + PyObject* root_key = RedBlackTree__transplant_values(self, Py_BuildValue("(OO)", node_idx, node_idx1)); + PyObject* new_indices = ArrayForTrees_delete(bt->tree, Py_BuildValue("(O)", node_idx1)); + if (new_indices != Py_None) { + bt->root_idx = PyDict_GetItem(new_indices, root_key); + } + } + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___leaf_case(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + PyObject* node_idx1 = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* walk = node_idx; + PyObject* walk1 = node_idx1; + PyObject* parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + long color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->color; + if (parent == Py_None) { + RedBlackTree__delete_root(self, Py_BuildValue("(OO)", walk, walk1)); + } + else { + if (RedBlackTree___walk1_walk_isblack(self, Py_BuildValue("(OO)", PyLong_FromLong(color), walk1)) == Py_True) { + RedBlackTree___fix_deletion(self, Py_BuildValue("(O)", walk)); + } + else { + PyObject* sibling_idx = RedBlackTree__get_sibling(self, Py_BuildValue("(O)", walk)); + if (sibling_idx != Py_None) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(sibling_idx)])->color = 1; + } + } + if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", walk)) == Py_True) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->left = Py_None; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->right = Py_None; + } + RedBlackTree__remove_node(self, Py_BuildValue("(O)", walk)); + } + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___one_child_case(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + PyObject* node_idx1 = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* walk = node_idx; + PyObject* walk1 = node_idx1; + long walk_original_color = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->color; + PyObject* parent = RedBlackTree__get_parent(self, Py_BuildValue("(O)", node_idx)); + if (parent == Py_None) { + RedBlackTree__delete_root(self, Py_BuildValue("(OO)", walk, walk1)); + } + else { + if (RedBlackTree__is_onleft(self, Py_BuildValue("(O)", walk)) == Py_True) { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->left = walk1; + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(parent)])->right = walk1; + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk1)])->parent = parent; + PyObject* a = RedBlackTree__remove_node(self, Py_BuildValue("(O)", walk)); + if (RedBlackTree___walk1_walk_isblack(self, Py_BuildValue("(OO)", PyLong_FromLong(walk_original_color), walk1)) == Py_True) { + RedBlackTree___fix_deletion(self, Py_BuildValue("(O)", walk1)); + } + else { + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk1)])->color = 0; + } + } + Py_RETURN_NONE; +} + +static PyObject* RedBlackTree___two_child_case(RedBlackTree* self, PyObject *args) { + PyObject* node_idx = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* walk = node_idx; + PyObject* successor = RedBlackTree__replace_node(self, Py_BuildValue("(O)", walk)); + RedBlackTree__transplant_values(self, Py_BuildValue("(OO)", walk, successor)); + walk = successor; + PyObject* walk1 = RedBlackTree__replace_node(self, Py_BuildValue("(O)", walk)); + + PyObject* ret = Py_BuildValue("(OO)", walk, walk1); + return ret; +} + +static PyObject* RedBlackTree_delete(RedBlackTree* self, PyObject *args, PyObject *kwds) { + PyObject* key = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* walk = BinarySearchTree_search(self->sbbt->bst, Py_BuildValue("(O)", key), PyDict_New()); + if (walk != Py_None) { + PyObject* walk1 = RedBlackTree__replace_node(self, Py_BuildValue("(O)", walk)); + if (RedBlackTree__has_two_child(self, Py_BuildValue("(O)", walk)) == Py_True) { + PyObject* tup = RedBlackTree___two_child_case(self, Py_BuildValue("(O)", walk)); + walk = PyObject_GetItem(tup, PyZero); + walk1 = PyObject_GetItem(tup, PyOne); + } + if (RedBlackTree__is_leaf(self, Py_BuildValue("(O)", walk)) == Py_True) { + RedBlackTree___leaf_case(self, Py_BuildValue("(OO)", walk, walk1)); + } + else if (RedBlackTree__has_one_child(self, Py_BuildValue("(O)", walk)) == Py_True) { + RedBlackTree___one_child_case(self, Py_BuildValue("(OO)", walk, walk1)); + } + Py_RETURN_TRUE; + } + else { + Py_RETURN_NONE; + } + Py_RETURN_NONE; +} + + static struct PyMethodDef RedBlackTree_PyMethodDef[] = { {"insert", (PyCFunction) RedBlackTree_insert, METH_VARARGS, NULL}, + {"delete", (PyCFunction) RedBlackTree_delete, METH_VARARGS | METH_KEYWORDS, NULL}, {"lower_bound", (PyCFunction) RedBlackTree_lower_bound, METH_VARARGS | METH_KEYWORDS, NULL}, {"upper_bound", (PyCFunction) RedBlackTree_upper_bound, METH_VARARGS | METH_KEYWORDS, NULL}, {"_get_parent", (PyCFunction) RedBlackTree__get_parent, METH_VARARGS, NULL}, diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 13dc8232..91bb62d7 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -542,8 +542,8 @@ def test_SplayTree(): assert [node.key for node in in_order] == [20, 30, 50, 55, 100, 200] assert [node.key for node in pre_order] == [200, 55, 50, 30, 20, 100] -def test_RedBlackTree(): - tree = RedBlackTree(backend=Backend.CPP) +def _test_RedBlackTree(backend): + tree = RedBlackTree(backend=backend) tree.insert(10, 10) tree.insert(18, 18) tree.insert(7, 7) @@ -558,7 +558,7 @@ def test_RedBlackTree(): tree.insert(6, 6) assert str(tree) == "[(11, 10, 10, 3), (10, 18, 18, None), (None, 7, 7, None), (None, 15, 15, None), (0, 16, 16, 6), (None, 30, 30, None), (1, 25, 25, 7), (5, 40, 40, 8), (None, 60, 60, None), (None, 2, 2, None), (None, 17, 17, None), (9, 6, 6, 2)]" - 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] == [2, 6, 7, 10, 15, 16, 17, 18, 25, 30, 40, 60] @@ -584,7 +584,7 @@ def test_RedBlackTree(): assert tree.upper_bound(60) is None assert tree.upper_bound(61) is None - tree = RedBlackTree(backend=Backend.CPP) + tree = RedBlackTree(backend=backend) assert tree.lower_bound(1) is None assert tree.upper_bound(0) is None @@ -611,7 +611,7 @@ def test_RedBlackTree(): assert tree._get_sibling(7) is None - 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, @@ -619,133 +619,138 @@ def test_RedBlackTree(): assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, 90, 110, 140, 130, 160, 150, 170, 180] - # tree.delete(180) - # tree.delete(130) - # tree.delete(110) - # tree.delete(190) - # 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, - # 120, 140, 150, 160, 170] - # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, - # 90, 160, 140, 150, 170] - - # tree.delete(170) - # tree.delete(100) - # tree.delete(60) - # 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] == [10, 20, 30, 40, 50, 70, 80, 90, 120, 140, 150, 160] - # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 70, 120, 90, 150, 140, 160] - - # tree.delete(70) - # tree.delete(140) - - # 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] == [10, 20, 30, 40, 50, 80, 90, 120, 150, 160] - # assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 120, 90, 150, 160] - - # tree.delete(150) - # tree.delete(120) - # 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] == [10, 20, 30, 40, 50, 80, 90, 160] - # assert [node.key for node in pre_order] == [40, 20, 10, 30, 80, 50, 90, 160] - - # tree.delete(50) - # tree.delete(80) - # 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] == [10, 20, 30, 40, 90, 160] - # assert [node.key for node in pre_order] == [40, 20, 10, 30, 90, 160] - - # tree.delete(30) - # tree.delete(20) - # 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] == [10, 40, 90, 160] - # assert [node.key for node in pre_order] == [40, 10, 90, 160] - - # tree.delete(10) - # 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] == [40, 90, 160] - # assert [node.key for node in pre_order] == [90, 40, 160] - - # tree.delete(40) - # tree.delete(90) - # 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] == [160] - # assert [node.key for node in pre_order] == [160] - - # tree.delete(160) - # 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 if node.key is not None] == [] - # assert [node.key for node in pre_order if node.key is not None] == [] - - # tree = RedBlackTree() - # tree.insert(50) - # tree.insert(40) - # tree.insert(30) - # tree.insert(20) - # tree.insert(10) - # tree.insert(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] == [5, 10, 20, 30, 40, 50] - # assert [node.key for node in pre_order] == [40, 20, 10, 5, 30, 50] - - # tree.delete(50) - # tree.delete(20) - # tree.delete(30) - - # 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] == [5, 10, 40] - # assert [node.key for node in pre_order] == [10, 5, 40] - - # tree = RedBlackTree() - # tree.insert(10) - # tree.insert(5) - # tree.insert(20) - # tree.insert(15) - - # 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] == [5, 10, 15, 20] - # assert [node.key for node in pre_order] == [10, 5, 20, 15] - - # tree.delete(5) - - # 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] == [10, 15, 20] - # assert [node.key for node in pre_order] == [15, 10, 20] - - # tree = RedBlackTree() - # tree.insert(10) - # tree.insert(5) - # tree.insert(20) - # tree.insert(15) - # tree.insert(2) - # tree.insert(6) - - # 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] == [2, 5, 6, 10, 15, 20] - # assert [node.key for node in pre_order] == [10, 5, 2, 6, 20, 15] - - # tree.delete(10) - - # 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] == [2, 5, 6, 15, 20] - # assert [node.key for node in pre_order] == [6, 5, 2, 20, 15] -test_RedBlackTree() + tree.delete(180) + tree.delete(130) + tree.delete(110) + tree.delete(190) + 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] == [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, + 120, 140, 150, 160, 170] + assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 60, 50, 70, 120, 100, + 90, 160, 140, 150, 170] + + tree.delete(170) + tree.delete(100) + tree.delete(60) + 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] == [10, 20, 30, 40, 50, 70, 80, 90, 120, 140, 150, 160] + assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 70, 120, 90, 150, 140, 160] + + tree.delete(70) + tree.delete(140) + + 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] == [10, 20, 30, 40, 50, 80, 90, 120, 150, 160] + assert [node.key for node in pre_order] == [80, 40, 20, 10, 30, 50, 120, 90, 150, 160] + + tree.delete(150) + tree.delete(120) + 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] == [10, 20, 30, 40, 50, 80, 90, 160] + assert [node.key for node in pre_order] == [40, 20, 10, 30, 80, 50, 90, 160] + + tree.delete(50) + tree.delete(80) + 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] == [10, 20, 30, 40, 90, 160] + assert [node.key for node in pre_order] == [40, 20, 10, 30, 90, 160] + + tree.delete(30) + tree.delete(20) + 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] == [10, 40, 90, 160] + assert [node.key for node in pre_order] == [40, 10, 90, 160] + + tree.delete(10) + 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] == [40, 90, 160] + assert [node.key for node in pre_order] == [90, 40, 160] + + tree.delete(40) + tree.delete(90) + 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] == [160] + assert [node.key for node in pre_order] == [160] + + tree.delete(160) + 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 if node.key is not None] == [] + assert [node.key for node in pre_order if node.key is not None] == [] + + tree = RedBlackTree(backend=backend) + tree.insert(50) + tree.insert(40) + tree.insert(30) + tree.insert(20) + tree.insert(10) + tree.insert(5) + + 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] == [5, 10, 20, 30, 40, 50] + assert [node.key for node in pre_order] == [40, 20, 10, 5, 30, 50] + + tree.delete(50) + tree.delete(20) + tree.delete(30) + + 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] == [5, 10, 40] + assert [node.key for node in pre_order] == [10, 5, 40] + + tree = RedBlackTree(backend=backend) + tree.insert(10) + tree.insert(5) + tree.insert(20) + tree.insert(15) + + 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] == [5, 10, 15, 20] + assert [node.key for node in pre_order] == [10, 5, 20, 15] + + tree.delete(5) + + 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] == [10, 15, 20] + assert [node.key for node in pre_order] == [15, 10, 20] + + tree = RedBlackTree(backend=backend) + tree.insert(10) + tree.insert(5) + tree.insert(20) + tree.insert(15) + tree.insert(2) + tree.insert(6) + + 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] == [2, 5, 6, 10, 15, 20] + assert [node.key for node in pre_order] == [10, 5, 2, 6, 20, 15] + + tree.delete(10) + + 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] == [2, 5, 6, 15, 20] + assert [node.key for node in pre_order] == [6, 5, 2, 20, 15] + +def test_RedBlackTree(): + _test_RedBlackTree(Backend.PYTHON) + +def test_cpp_RedBlackTree(): + _test_RedBlackTree(Backend.CPP) From 10ef2740dd73d88aba9914c8678aa2d3b1aca4eb Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Tue, 11 Jun 2024 16:15:40 +0530 Subject: [PATCH 7/9] code quality --- pydatastructs/trees/_backend/cpp/RedBlackTree.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp index d87afaaf..a3875bd9 100644 --- a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -459,7 +459,7 @@ static PyObject* RedBlackTree__delete_root(RedBlackTree* self, PyObject *args) { if (RedBlackTree__is_leaf(self, Py_BuildValue("(O)", node_idx)) == Py_True) { reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->data = Py_None; reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->key = Py_None; - } + } else if (RedBlackTree__has_one_child(self, Py_BuildValue("(O)", node_idx)) == Py_True) { PyObject* root_key = RedBlackTree__transplant_values(self, Py_BuildValue("(OO)", node_idx, node_idx1)); PyObject* new_indices = ArrayForTrees_delete(bt->tree, Py_BuildValue("(O)", node_idx1)); From d70191ee462cd5aa0f33c19d594f721d90faf4f4 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Tue, 11 Jun 2024 16:26:29 +0530 Subject: [PATCH 8/9] RedBlackTrees search() --- pydatastructs/trees/_backend/cpp/RedBlackTree.hpp | 5 +++++ pydatastructs/trees/tests/test_binary_trees.py | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp index a3875bd9..cfbebc43 100644 --- a/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -574,10 +574,15 @@ static PyObject* RedBlackTree_delete(RedBlackTree* self, PyObject *args, PyObjec Py_RETURN_NONE; } +static PyObject* RedBlackTree_search(RedBlackTree* self, PyObject *args, PyObject *kwds) { + return BinarySearchTree_search(self->sbbt->bst, args, kwds); +} + static struct PyMethodDef RedBlackTree_PyMethodDef[] = { {"insert", (PyCFunction) RedBlackTree_insert, METH_VARARGS, NULL}, {"delete", (PyCFunction) RedBlackTree_delete, METH_VARARGS | METH_KEYWORDS, NULL}, + {"search", (PyCFunction) RedBlackTree_search, METH_VARARGS | METH_KEYWORDS, NULL}, {"lower_bound", (PyCFunction) RedBlackTree_lower_bound, METH_VARARGS | METH_KEYWORDS, NULL}, {"upper_bound", (PyCFunction) RedBlackTree_upper_bound, METH_VARARGS | METH_KEYWORDS, NULL}, {"_get_parent", (PyCFunction) RedBlackTree__get_parent, METH_VARARGS, NULL}, diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 91bb62d7..523b138f 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -700,9 +700,15 @@ def _test_RedBlackTree(backend): assert [node.key for node in in_order] == [5, 10, 20, 30, 40, 50] assert [node.key for node in pre_order] == [40, 20, 10, 5, 30, 50] + assert tree.search(50) == 0 + assert tree.search(20) == 3 + assert tree.search(30) == 2 tree.delete(50) tree.delete(20) tree.delete(30) + assert tree.search(50) is None + assert tree.search(20) is None + assert tree.search(30) is None in_order = trav.depth_first_search(order='in_order') pre_order = trav.depth_first_search(order='pre_order') From a6ad1d1ece05c87a751213c2019b4c49eae83d83 Mon Sep 17 00:00:00 2001 From: Kishan-Ved Date: Tue, 11 Jun 2024 16:48:25 +0530 Subject: [PATCH 9/9] RedBlackTrees C++ backend benchmark test --- .../tests/benchmarks/test_binary_trees.py | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/pydatastructs/trees/tests/benchmarks/test_binary_trees.py b/pydatastructs/trees/tests/benchmarks/test_binary_trees.py index c0ab14ce..689c9353 100644 --- a/pydatastructs/trees/tests/benchmarks/test_binary_trees.py +++ b/pydatastructs/trees/tests/benchmarks/test_binary_trees.py @@ -1,5 +1,5 @@ import timeit, functools, os, pytest -from pydatastructs.trees.binary_trees import (BinarySearchTree) +from pydatastructs.trees.binary_trees import (BinarySearchTree, RedBlackTree) from pydatastructs.utils.misc_util import Backend @pytest.mark.xfail @@ -22,7 +22,55 @@ def g(backend, tree): for node in range(-1000, 1000): tree.search(node) def h(backend, tree): - for node in range(2000): + for node in range(-1000, 1000): + tree.delete(node) + + kwds_dict_PY = {"backend": Backend.PYTHON, "tree":b1} + kwds_dict_CPP = {"backend": Backend.CPP, "tree":b2} + + timer_python = timeit.Timer(functools.partial(f, **kwds_dict_PY)) + python_insert = min(timer_python.repeat(repeat, number)) + + timer_cpp = timeit.Timer(functools.partial(f, **kwds_dict_CPP)) + cpp_insert = min(timer_cpp.repeat(repeat, number)) + assert cpp_insert < python_insert + + timer_python = timeit.Timer(functools.partial(g, **kwds_dict_PY)) + python_search = min(timer_python.repeat(repeat, number)) + + timer_cpp = timeit.Timer(functools.partial(g, **kwds_dict_CPP)) + cpp_search = min(timer_cpp.repeat(repeat, number)) + assert cpp_search < python_search + + timer_python = timeit.Timer(functools.partial(h, **kwds_dict_PY)) + python_delete = min(timer_python.repeat(repeat, number)) + + timer_cpp = timeit.Timer(functools.partial(h, **kwds_dict_CPP)) + cpp_delete = min(timer_cpp.repeat(repeat, number)) + assert cpp_delete < python_delete + +@pytest.mark.xfail +def test_RedBlackTree(**kwargs): + cpp = Backend.CPP + repeat = 1 + number = 1 + + size = int(os.environ.get("PYDATASTRUCTS_BENCHMARK_SIZE", "1000")) + size = kwargs.get("size", size) + + RBT = RedBlackTree + b1 = RBT(backend=Backend.PYTHON) + b2 = RBT(backend=Backend.CPP) + + def f(backend, tree): + for node in range(-1000,1000): + tree.insert(node, node) + + def g(backend, tree): + for node in range(-1000, 1000): + tree.search(node) + def h(backend, tree): + for node in range(-1000, 1000): tree.delete(node) kwds_dict_PY = {"backend": Backend.PYTHON, "tree":b1}