diff --git a/pydatastructs/trees/_backend/cpp/BinaryIndexedTree.hpp b/pydatastructs/trees/_backend/cpp/BinaryIndexedTree.hpp index 56235056..39957fac 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryIndexedTree.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryIndexedTree.hpp @@ -66,11 +66,11 @@ static PyObject* BinaryIndexedTree___new__(PyTypeObject* type, PyObject *args, P } self->array = reinterpret_cast(_one_dimensional_array); self->tree = PyList_New(self->array->_size+2); - for(int i=0;iarray->_size+2;i++){ + for(int i=0;iarray->_size+2;i++) { PyList_SetItem(self->tree, i, PyZero); } self->flag = PyList_New(self->array->_size); - for(int i=0;iarray->_size;i++){ + for(int i=0;iarray->_size;i++) { PyList_SetItem(self->flag, i, PyZero); BinaryIndexedTree_update(self, Py_BuildValue("(OO)", PyLong_FromLong(i), self->array->_data[i])); } diff --git a/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp b/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp index 482a0330..01bd8226 100644 --- a/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp +++ b/pydatastructs/trees/_backend/cpp/BinarySearchTree.hpp @@ -103,7 +103,7 @@ static PyObject* BinarySearchTree_search(BinarySearchTree* self, PyObject* args, PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments = Py_BuildValue("OO", key, curr_key); + PyObject* arguments = Py_BuildValue("(OO)", key, curr_key); PyObject* res = PyObject_CallObject(bt->comparator, arguments); Py_DECREF(arguments); if (!PyLong_Check(res)) { @@ -125,7 +125,7 @@ static PyObject* BinarySearchTree_search(BinarySearchTree* self, PyObject* args, return walk; } else { - return Py_BuildValue("OO",walk,parent); + return Py_BuildValue("(OO)",walk,parent); } Py_RETURN_NONE; // dummy return statement, never executed } @@ -168,7 +168,7 @@ static PyObject* BinarySearchTree_insert(BinarySearchTree* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments = Py_BuildValue("OO", key, curr_key); + PyObject* arguments = Py_BuildValue("(OO)", key, curr_key); PyObject* cres = PyObject_CallObject(bt->comparator, arguments); Py_DECREF(arguments); if (!PyLong_Check(cres)) { @@ -359,7 +359,7 @@ static PyObject* BinarySearchTree__bound_helper(BinarySearchTree* self, PyObject PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments = Py_BuildValue("OO", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->key, bound_key); + PyObject* arguments = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node_idx)])->key, bound_key); PyObject* cres = PyObject_CallObject(bt->comparator, arguments); Py_DECREF(arguments); if (!PyLong_Check(cres)) { @@ -481,7 +481,7 @@ static PyObject* BinarySearchTree__lca_2(BinarySearchTree* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments1 = Py_BuildValue("OO", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(u)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); + PyObject* arguments1 = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(u)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); PyObject* cres1 = PyObject_CallObject(bt->comparator, arguments1); Py_DECREF(arguments1); if (!PyLong_Check(cres1)) { @@ -494,7 +494,7 @@ static PyObject* BinarySearchTree__lca_2(BinarySearchTree* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments2 = Py_BuildValue("OO", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(v)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); + PyObject* arguments2 = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(v)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); PyObject* cres2 = PyObject_CallObject(bt->comparator, arguments2); Py_DECREF(arguments2); if (!PyLong_Check(cres2)) { @@ -522,7 +522,7 @@ static PyObject* BinarySearchTree__lca_2(BinarySearchTree* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments1 = Py_BuildValue("OO", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(u)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); + PyObject* arguments1 = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(u)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); PyObject* cres1 = PyObject_CallObject(bt->comparator, arguments1); Py_DECREF(arguments1); if (!PyLong_Check(cres1)) { @@ -535,7 +535,7 @@ static PyObject* BinarySearchTree__lca_2(BinarySearchTree* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments2 = Py_BuildValue("OO", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(v)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); + PyObject* arguments2 = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(v)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(curr_root)])->key); PyObject* cres2 = PyObject_CallObject(bt->comparator, arguments2); Py_DECREF(arguments2); if (!PyLong_Check(cres2)) { @@ -616,7 +616,7 @@ static PyObject* BinarySearchTree_select(BinarySearchTree* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments = Py_BuildValue("OO", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(left_walk)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->key); + PyObject* arguments = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(left_walk)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->key); PyObject* cres = PyObject_CallObject(bt->comparator, arguments); Py_DECREF(arguments); if (!PyLong_Check(cres)) { @@ -637,7 +637,7 @@ static PyObject* BinarySearchTree_select(BinarySearchTree* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "comparator should be callable"); return NULL; } - PyObject* arguments = Py_BuildValue("OO", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(right_walk)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->key); + PyObject* arguments = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(right_walk)])->key, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->key); PyObject* cres = PyObject_CallObject(bt->comparator, arguments); Py_DECREF(arguments); if (!PyLong_Check(cres)) { diff --git a/pydatastructs/trees/_backend/cpp/BinaryTree.hpp b/pydatastructs/trees/_backend/cpp/BinaryTree.hpp index f07eab4a..72b67090 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryTree.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryTree.hpp @@ -122,10 +122,10 @@ static struct PyMethodDef BinaryTree_PyMethodDef[] = { }; static PyMemberDef BinaryTree_PyMemberDef[] = { - {"root_idx", T_OBJECT, offsetof(BinaryTree, root_idx), READONLY, "Index of the root node"}, + {"root_idx", T_OBJECT_EX, offsetof(BinaryTree, root_idx), 0, "Index of the root node"}, {"comparator", T_OBJECT, offsetof(BinaryTree, comparator), 0, "Comparator function"}, {"tree", T_OBJECT_EX, offsetof(BinaryTree, tree), 0, "Tree"}, - {"size", T_LONG, offsetof(BinaryTree, size), READONLY, "Size of the tree"}, + {"size", T_LONG, offsetof(BinaryTree, size), 0, "Size of the tree"}, {"is_order_statistic", T_LONG, offsetof(BinaryTree, is_order_statistic), 0, "Whether the tree is ordered statically or not"}, {NULL} /* Sentinel */ }; diff --git a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index c85d6b12..8971597a 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp @@ -15,6 +15,7 @@ #include "BinarySearchTree.hpp" #include "SelfBalancingBinaryTree.hpp" #include "RedBlackTree.hpp" +#include "SplayTree.hpp" typedef struct { PyObject_HEAD @@ -40,8 +41,14 @@ static PyObject* BinaryTreeTraversal___new__(PyTypeObject* type, PyObject *args, 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 (PyType_Ready(&SplayTreeType) < 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)) { + if (PyObject_IsInstance(tree, (PyObject *)&SplayTreeType)) { + self->tree = reinterpret_cast(tree)->sbbt->bst->binary_tree; + } + else if (PyObject_IsInstance(tree, (PyObject *)&RedBlackTreeType)) { self->tree = reinterpret_cast(tree)->sbbt->bst->binary_tree; } else if (PyObject_IsInstance(tree, (PyObject *)&SelfBalancingBinaryTreeType)) { diff --git a/pydatastructs/trees/_backend/cpp/SplayTree.hpp b/pydatastructs/trees/_backend/cpp/SplayTree.hpp new file mode 100644 index 00000000..b26041d9 --- /dev/null +++ b/pydatastructs/trees/_backend/cpp/SplayTree.hpp @@ -0,0 +1,353 @@ +#ifndef TREES_SPLAYTREE_HPP +#define TREES_SPLAYTREE_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 "BinaryTreeTraversal.hpp" +#include "BinarySearchTree.hpp" +#include "SelfBalancingBinaryTree.hpp" + +typedef struct { + PyObject_HEAD + SelfBalancingBinaryTree* sbbt; + ArrayForTrees* tree; + PyTypeObject* type; +} SplayTree; + +static void SplayTree_dealloc(SplayTree *self) { + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +static PyObject* SplayTree___new__(PyTypeObject* type, PyObject *args, PyObject *kwds) { + SplayTree *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; + self->type = type; + + return reinterpret_cast(self); +} + +static PyObject* SplayTree___str__(SplayTree *self) { + return BinarySearchTree___str__(self->sbbt->bst); +} + +static PyObject* SplayTree__zig(SplayTree *self, PyObject* args) { + PyObject* x = PyObject_GetItem(args, PyZero); + PyObject* p = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->left == x) { + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", p, x)); + } + else { + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", p, x)); + } + + Py_RETURN_NONE; +} + +static PyObject* SplayTree__zig_zig(SplayTree *self, PyObject* args) { + PyObject* x = PyObject_GetItem(args, PyZero); + PyObject* p = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent, p)); + SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", p, x)); + + Py_RETURN_NONE; +} + +static PyObject* SplayTree__zig_zag(SplayTree *self, PyObject* args) { + PyObject* p = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + SelfBalancingBinaryTree__left_right_rotate(self->sbbt, Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent, p)); + + Py_RETURN_NONE; +} + +static PyObject* SplayTree__zag_zag(SplayTree *self, PyObject* args) { + PyObject* x = PyObject_GetItem(args, PyZero); + PyObject* p = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent, p)); + SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", p, x)); + + Py_RETURN_NONE; +} + +static PyObject* SplayTree__zag_zig(SplayTree *self, PyObject* args) { + PyObject* p = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + SelfBalancingBinaryTree__right_left_rotate(self->sbbt, Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent, p)); + + Py_RETURN_NONE; +} + +static PyObject* SplayTree_splay(SplayTree *self, PyObject* args) { + PyObject* x = PyObject_GetItem(args, PyZero); + PyObject* p = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + while (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(x)])->parent != Py_None) { + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent == Py_None) { + SplayTree__zig(self, Py_BuildValue("(OO)", x, p)); + } + else if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->left == x && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent)])->left == p) { + SplayTree__zig_zig(self, Py_BuildValue("(OO)", x, p)); + } + else if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->right == x && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent)])->right == p) { + SplayTree__zag_zag(self, Py_BuildValue("(OO)", x, p)); + } + else if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->left == x && reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(p)])->parent)])->right == p) { + SplayTree__zag_zig(self, Py_BuildValue("(O)", p)); + } + else { + SplayTree__zig_zag(self, Py_BuildValue("(O)", p)); + } + p = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(x)])->parent; + } + + Py_RETURN_NONE; +} + +static PyObject* SplayTree_insert(SplayTree *self, PyObject* args) { + PyObject* key = PyObject_GetItem(args, PyZero); + PyObject* x = PyObject_GetItem(args, PyOne); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + SelfBalancingBinaryTree_insert(self->sbbt, args); + PyObject* kwd_parent = PyDict_New(); + PyDict_SetItemString(kwd_parent, "parent", PyLong_FromLong(1)); + PyObject* tup = SelfBalancingBinaryTree_search(self->sbbt, Py_BuildValue("(O)", key), kwd_parent); + PyObject* e = PyTuple_GetItem(tup, 0); + PyObject* p = PyTuple_GetItem(tup, 1); + reinterpret_cast(bt->tree->_one_dimensional_array->_data[bt->size-1])->parent = p; + SplayTree_splay(self, Py_BuildValue("(OO)", e, p)); + + Py_RETURN_NONE; +} + +static PyObject* SplayTree_delete(SplayTree *self, PyObject* args) { + PyObject* x = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* kwd_parent = PyDict_New(); + PyDict_SetItemString(kwd_parent, "parent", PyLong_FromLong(1)); + PyObject* tup = SelfBalancingBinaryTree_search(self->sbbt, Py_BuildValue("(O)", x), kwd_parent); + PyObject* e = PyTuple_GetItem(tup, 0); + PyObject* p = PyTuple_GetItem(tup, 1); + if (e == Py_None) { + Py_RETURN_NONE; + } + SplayTree_splay(self, Py_BuildValue("(OO)", e, p)); + PyObject* status = SelfBalancingBinaryTree_delete(self->sbbt, Py_BuildValue("(O)", x), PyDict_New()); + + return status; +} + +static PyObject* SplayTree_join(SplayTree *self, PyObject* args) { + SplayTree* other = reinterpret_cast(PyObject_GetItem(args, PyZero)); + BinaryTree* bt = self->sbbt->bst->binary_tree; + BinaryTree* obt = other->sbbt->bst->binary_tree; + + PyObject* maxm = bt->root_idx; + while (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(maxm)])->right != Py_None) { + maxm = reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(maxm)])->right; + } + PyObject* minm = obt->root_idx; + while (reinterpret_cast(obt->tree->_one_dimensional_array->_data[PyLong_AsLong(minm)])->left != Py_None) { + minm = reinterpret_cast(obt->tree->_one_dimensional_array->_data[PyLong_AsLong(minm)])->left; + } + + if (!PyCallable_Check(bt->comparator)) { + PyErr_SetString(PyExc_ValueError, "comparator should be callable"); + return NULL; + } + PyObject* arguments = Py_BuildValue("(OO)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(maxm)])->key, reinterpret_cast(obt->tree->_one_dimensional_array->_data[PyLong_AsLong(minm)])->key); + PyObject* cres = PyObject_CallObject(bt->comparator, arguments); + Py_DECREF(arguments); + if (!PyLong_Check(cres)) { + PyErr_SetString(PyExc_TypeError, "bad return type from comparator"); + return NULL; + } + long long comp = PyLong_AsLongLong(cres); + if (comp == 0) { + PyErr_SetString(PyExc_ValueError, "Elements of existing Splay Tree aren't less than that of the new Splay tree."); + return NULL; + } + + SplayTree_splay(self, Py_BuildValue("(OO)", maxm, reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(maxm)])->parent)); + long idx_update = bt->tree->_one_dimensional_array->_size; + long n = obt->tree->_one_dimensional_array->_size; + for (int i=0; itree->_one_dimensional_array->_data[i]; + if (node != Py_None) { + TreeNode* treenode = reinterpret_cast(node); + 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* node_copy = reinterpret_cast(TreeNode___new__(&TreeNodeType, Py_BuildValue("(OO)", treenode->key, treenode->data), PyDict_New())); + if (treenode->left != Py_None) { + node_copy->left = PyLong_FromLong(PyLong_AsLong(treenode->left) + idx_update); + } + if (treenode->right != Py_None) { + node_copy->right = PyLong_FromLong(PyLong_AsLong(treenode->right) + idx_update); + } + ArrayForTrees_append(bt->tree, Py_BuildValue("(O)", node_copy)); + } + else { + ArrayForTrees_append(bt->tree, Py_BuildValue("(O)", node)); + } + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->right = PyLong_FromLong(PyLong_AsLong(obt->root_idx) + idx_update); + + Py_RETURN_NONE; +} + +static PyObject* SplayTree__pre_order(SplayTree* self, PyObject *args) { + long node = PyLong_AsLong(PyObject_GetItem(args, PyZero)); + PyObject* visit = PyList_New(0); + ArrayForTrees* tree = self->sbbt->bst->binary_tree->tree; + long size = self->sbbt->bst->binary_tree->size; + std::stack s; + s.push(node); + + while (!s.empty()) { + node = s.top(); + s.pop(); + TreeNode* curr_node = reinterpret_cast(tree->_one_dimensional_array->_data[node]); + PyList_Append(visit, reinterpret_cast(curr_node)); + if (curr_node->right != Py_None) { + s.push(PyLong_AsLong(curr_node->right)); + } + if (curr_node->left != Py_None) { + s.push(PyLong_AsLong(curr_node->left)); + } + } + return visit; +} + +static PyObject* SplayTree_split(SplayTree *self, PyObject* args) { + PyObject* x = PyObject_GetItem(args, PyZero); + BinaryTree* bt = self->sbbt->bst->binary_tree; + + PyObject* kwd_parent = PyDict_New(); + PyDict_SetItemString(kwd_parent, "parent", PyLong_FromLong(1)); + PyObject* tup = SelfBalancingBinaryTree_search(self->sbbt, Py_BuildValue("(O)", x), kwd_parent); + PyObject* e = PyTuple_GetItem(tup, 0); + PyObject* p = PyTuple_GetItem(tup, 1); + if (e == Py_None) { + Py_RETURN_NONE; + } + SplayTree_splay(self, Py_BuildValue("(OO)", e, p)); + if (PyType_Ready(self->type) < 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; + } + + Py_INCREF(Py_None); + Py_INCREF(Py_None); + if (!PyCallable_Check(bt->comparator)) { + PyErr_SetString(PyExc_ValueError, "comparator should be callable"); + return NULL; + } + SplayTree* other = reinterpret_cast(SplayTree___new__(self->type, Py_BuildValue("(OOOO)", Py_None, Py_None, bt->comparator, PyZero), PyDict_New())); + + // SplayTree* other = reinterpret_cast(PyObject_GetItem(args, PyOne)); + if (reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->right != Py_None) { + // if (PyType_Ready(&BinaryTreeTraversalType) < 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; + // } + // BinaryTreeTraversal* traverse = reinterpret_cast(BinaryTreeTraversal___new__(&BinaryTreeTraversalType, Py_BuildValue("(O)", self), PyDict_New())); + // PyObject* kwd_dict = PyDict_New(); + // PyDict_SetItemString(kwd_dict, "node", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->right); + // PyDict_SetItemString(kwd_dict, "order", PyUnicode_FromString("pre_order")); + // PyObject* elements = BinaryTreeTraversal_depth_first_search(traverse, Py_BuildValue("()"), kwd_dict); + PyObject* elements = SplayTree__pre_order(self, Py_BuildValue("(O)", reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->right)); + for (int i=0; isbbt, Py_BuildValue("(OO)", reinterpret_cast( PyList_GetItem(elements, i))->key, reinterpret_cast( PyList_GetItem(elements, i))->data)); + } + for (int j=PyList_Size(elements)-1; j>-1; j--) { + tup = SelfBalancingBinaryTree_search(self->sbbt, Py_BuildValue("(O)", reinterpret_cast( PyList_GetItem(elements, j))->key), kwd_parent); + e = PyTuple_GetItem(tup, 0); + p = PyTuple_GetItem(tup, 1); + bt->tree->_one_dimensional_array->_data[PyLong_AsLong(e)] = Py_None; + } + reinterpret_cast(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(bt->root_idx)])->right = Py_None; + } + + return reinterpret_cast(other); +} + +static struct PyMethodDef SplayTree_PyMethodDef[] = { + {"insert", (PyCFunction) SplayTree_insert, METH_VARARGS, NULL}, + {"delete", (PyCFunction) SplayTree_delete, METH_VARARGS, NULL}, + {"join", (PyCFunction) SplayTree_join, METH_VARARGS, NULL}, + {"split", (PyCFunction) SplayTree_split, METH_VARARGS, NULL}, + {NULL} +}; + + +static PyMemberDef SplayTree_PyMemberDef[] = { + {"tree", T_OBJECT_EX, offsetof(SplayTree, tree), 0, "tree"}, + {NULL} /* Sentinel */ +}; + + +static PyTypeObject SplayTreeType = { + /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "SplayTree", + /* tp_basicsize */ sizeof(SplayTree), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor) SplayTree_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) SplayTree___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 */ SplayTree_PyMethodDef, + /* tp_members */ SplayTree_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 */ SplayTree___new__, +}; + + + +#endif diff --git a/pydatastructs/trees/_backend/cpp/trees.cpp b/pydatastructs/trees/_backend/cpp/trees.cpp index 5cbb3c18..00b7316d 100644 --- a/pydatastructs/trees/_backend/cpp/trees.cpp +++ b/pydatastructs/trees/_backend/cpp/trees.cpp @@ -5,6 +5,7 @@ #include "SelfBalancingBinaryTree.hpp" #include "RedBlackTree.hpp" #include "BinaryIndexedTree.hpp" +#include "SplayTree.hpp" static struct PyModuleDef trees_struct = { PyModuleDef_HEAD_INIT, @@ -54,5 +55,11 @@ PyMODINIT_FUNC PyInit__trees(void) { Py_INCREF(&BinaryIndexedTreeType); PyModule_AddObject(trees, "BinaryIndexedTree", reinterpret_cast(&BinaryIndexedTreeType)); + if (PyType_Ready(&SplayTreeType) < 0) { + return NULL; + } + Py_INCREF(&SplayTreeType); + PyModule_AddObject(trees, "SplayTree", reinterpret_cast(&SplayTreeType)); + return trees; } diff --git a/pydatastructs/trees/binary_trees.py b/pydatastructs/trees/binary_trees.py index 816d1bc8..d914b8ab 100644 --- a/pydatastructs/trees/binary_trees.py +++ b/pydatastructs/trees/binary_trees.py @@ -1044,9 +1044,18 @@ class SplayTree(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.SplayTree(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', 'join', 'split'] + return ['__new__', 'insert', 'delete', 'join', 'split'] def _zig(self, x, p): if self.tree[p].left == x: diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 3852c926..c13f3851 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -487,16 +487,17 @@ def test_SelfBalancingBinaryTree(): def test_cpp_SelfBalancingBinaryTree(): _test_SelfBalancingBinaryTree(Backend.CPP) -def test_SplayTree(): - t = SplayTree(100, 100) +def _test_SplayTree(backend): + t = SplayTree(100, 100, backend=backend) t.insert(50, 50) t.insert(200, 200) t.insert(40, 40) t.insert(30, 30) t.insert(20, 20) t.insert(55, 55) + assert str(t) == "[(None, 100, 100, None), (None, 50, 50, None), (0, 200, 200, None), (None, 40, 40, 1), (5, 30, 30, 3), (None, 20, 20, None), (4, 55, 55, 2)]" - trav = BinaryTreeTraversal(t) + trav = BinaryTreeTraversal(t, 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] == [20, 30, 40, 50, 55, 100, 200] @@ -516,36 +517,46 @@ 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] == [50, 30, 20, 55, 200, 100] - t1 = SplayTree(1000, 1000) + t1 = SplayTree(1000, 1000, backend=backend) t1.insert(2000, 2000) - trav = BinaryTreeTraversal(t1) - in_order = trav.depth_first_search(order='in_order') - pre_order = trav.depth_first_search(order='pre_order') + trav2 = BinaryTreeTraversal(t1, backend=backend) + in_order = trav2.depth_first_search(order='in_order') + pre_order = trav2.depth_first_search(order='pre_order') assert [node.key for node in in_order] == [1000, 2000] assert [node.key for node in pre_order] == [2000, 1000] t.join(t1) + assert str(t) == "[(None, 100, 100, None), '', (6, 200, 200, 8), (4, 50, 50, None), (5, 30, 30, None), (None, 20, 20, None), (3, 55, 55, 0), (None, 1000, 1000, None), (7, 2000, 2000, None), '']" - trav = BinaryTreeTraversal(t) - 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] == [20, 30, 50, 55, 100, 200, 1000, 2000] - assert [node.key for node in pre_order] == [200, 55, 50, 30, 20, 100, 2000, 1000] + if backend == Backend.PYTHON: + trav3 = BinaryTreeTraversal(t, backend=backend) + in_order = trav3.depth_first_search(order='in_order') + pre_order = trav3.depth_first_search(order='pre_order') + assert [node.key for node in in_order] == [20, 30, 50, 55, 100, 200, 1000, 2000] + assert [node.key for node in pre_order] == [200, 55, 50, 30, 20, 100, 2000, 1000] s = t.split(200) + assert str(s) == "[(1, 2000, 2000, None), (None, 1000, 1000, None)]" - trav = BinaryTreeTraversal(s) - in_order = trav.depth_first_search(order='in_order') - pre_order = trav.depth_first_search(order='pre_order') + trav4 = BinaryTreeTraversal(s, backend=backend) + in_order = trav4.depth_first_search(order='in_order') + pre_order = trav4.depth_first_search(order='pre_order') assert [node.key for node in in_order] == [1000, 2000] assert [node.key for node in pre_order] == [2000, 1000] - trav = BinaryTreeTraversal(t) - 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] == [20, 30, 50, 55, 100, 200] - assert [node.key for node in pre_order] == [200, 55, 50, 30, 20, 100] + if backend == Backend.PYTHON: + trav5 = BinaryTreeTraversal(t, backend=backend) + in_order = trav5.depth_first_search(order='in_order') + pre_order = trav5.depth_first_search(order='pre_order') + 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_SplayTree(): + _test_SplayTree(Backend.PYTHON) + +def test_cpp_SplayTree(): + _test_SplayTree(Backend.CPP) def _test_RedBlackTree(backend): tree = RedBlackTree(backend=backend)