diff --git a/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp b/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp index 0a920db87..482a03302 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/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index 5c464787c..c85d6b127 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/_backend/cpp/RedBlackTree.hpp b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp new file mode 100644 index 000000000..cfbebc438 --- /dev/null +++ b/pydatastructs/trees/_backend/cpp/RedBlackTree.hpp @@ -0,0 +1,641 @@ +#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 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 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 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 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}, + {"_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} +}; + +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 f499c9bf0..7e91d1a52 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 bd8280da7..a48113f40 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 cdc778539..54bb7be52 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 diff --git a/pydatastructs/trees/tests/benchmarks/test_binary_trees.py b/pydatastructs/trees/tests/benchmarks/test_binary_trees.py index c0ab14ce4..689c9353b 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} diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 3b41d8254..523b138ff 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() +def _test_RedBlackTree(backend): + tree = RedBlackTree(backend=backend) tree.insert(10, 10) tree.insert(18, 18) tree.insert(7, 7) @@ -556,8 +556,9 @@ def test_RedBlackTree(): tree.insert(2, 2) tree.insert(17, 17) 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) + 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] @@ -583,7 +584,7 @@ def test_RedBlackTree(): assert tree.upper_bound(60) is None assert tree.upper_bound(61) is None - tree = RedBlackTree() + tree = RedBlackTree(backend=backend) assert tree.lower_bound(1) is None assert tree.upper_bound(0) is None @@ -606,10 +607,11 @@ def test_RedBlackTree(): 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) + 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, @@ -684,7 +686,7 @@ def test_RedBlackTree(): 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 = RedBlackTree(backend=backend) tree.insert(50) tree.insert(40) tree.insert(30) @@ -692,28 +694,34 @@ def test_RedBlackTree(): tree.insert(10) tree.insert(5) - trav = BinaryTreeTraversal(tree) + trav = BinaryTreeTraversal(tree, backend=backend) in_order = trav.depth_first_search(order='in_order') pre_order = trav.depth_first_search(order='pre_order') assert [node.key for node in in_order] == [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') 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 = RedBlackTree(backend=backend) tree.insert(10) tree.insert(5) tree.insert(20) tree.insert(15) - trav = BinaryTreeTraversal(tree) + trav = BinaryTreeTraversal(tree, backend=backend) in_order = trav.depth_first_search(order='in_order') pre_order = trav.depth_first_search(order='pre_order') assert [node.key for node in in_order] == [5, 10, 15, 20] @@ -726,7 +734,7 @@ def test_RedBlackTree(): 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 = RedBlackTree(backend=backend) tree.insert(10) tree.insert(5) tree.insert(20) @@ -734,7 +742,7 @@ def test_RedBlackTree(): tree.insert(2) tree.insert(6) - trav = BinaryTreeTraversal(tree) + trav = BinaryTreeTraversal(tree,backend=backend) in_order = trav.depth_first_search(order='in_order') pre_order = trav.depth_first_search(order='pre_order') assert [node.key for node in in_order] == [2, 5, 6, 10, 15, 20] @@ -746,3 +754,9 @@ def test_RedBlackTree(): 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) diff --git a/pydatastructs/utils/_backend/cpp/TreeNode.hpp b/pydatastructs/utils/_backend/cpp/TreeNode.hpp index 41c64f724..e7ed2841b 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}, };