Skip to content

Commit

Permalink
C++ backend for Treap (#568)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kishan-Ved authored Jul 19, 2024
1 parent 4b2272f commit 35844a2
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 13 deletions.
2 changes: 1 addition & 1 deletion pydatastructs/trees/_backend/cpp/BinaryTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ static PyObject* BinaryTree___str__(BinaryTree *self) {
if (reinterpret_cast<PyObject*>(node) != Py_None) {
PyObject* out;
if (node->isCartesianTreeNode == true) {
out = Py_BuildValue("(OOOOO)", node->left, node->key, PyLong_FromLong(node->priority), node->data, node->right);
out = Py_BuildValue("(OOOOO)", node->left, node->key, PyFloat_FromDouble(node->priority), node->data, node->right);
}
else {
out = Py_BuildValue("(OOOO)", node->left, node->key, node->data, node->right);
Expand Down
2 changes: 1 addition & 1 deletion pydatastructs/trees/_backend/cpp/CartesianTree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static PyObject* CartesianTree_insert(CartesianTree *self, PyObject* args) {
}
TreeNode* new_node = reinterpret_cast<TreeNode*>(TreeNode___new__(&TreeNodeType, Py_BuildValue("(OO)", key, data), PyDict_New()));
new_node->isCartesianTreeNode = true;
new_node->priority = PyLong_AsLong(priority);
new_node->priority = PyFloat_AsDouble(priority);
new_node->parent = node->parent;
new_node->left = node->left;
new_node->right = node->right;
Expand Down
119 changes: 119 additions & 0 deletions pydatastructs/trees/_backend/cpp/Treap.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#ifndef TREES_TREAP_HPP
#define TREES_TREAP_HPP

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <structmember.h>
#include <cstdlib>
#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"
#include "CartesianTree.hpp"

typedef struct {
PyObject_HEAD
CartesianTree* ct;
ArrayForTrees* tree;
} Treap;

static void Treap_dealloc(Treap *self) {
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
}

static PyObject* Treap___new__(PyTypeObject* type, PyObject *args, PyObject *kwds) {
Treap *self;
self = reinterpret_cast<Treap*>(type->tp_alloc(type, 0));

if (PyType_Ready(&CartesianTreeType) < 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 = CartesianTree___new__(&CartesianTreeType, args, kwds);
self->ct = reinterpret_cast<CartesianTree*>(p);
self->tree = reinterpret_cast<CartesianTree*>(p)->sbbt->bst->binary_tree->tree;

return reinterpret_cast<PyObject*>(self);
}

static PyObject* Treap___str__(Treap *self) {
return CartesianTree___str__(self->ct);
}

static PyObject* Treap_search(Treap* self, PyObject *args, PyObject *kwds) {
return CartesianTree_search(self->ct, args, kwds);
}

static PyObject* Treap_delete(Treap* self, PyObject *args, PyObject *kwds) {
return CartesianTree_delete(self->ct, args, kwds);
}

static PyObject* Treap_insert(Treap *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;
}
PyObject* priority = PyFloat_FromDouble(((double) rand() / (RAND_MAX)));

return CartesianTree_insert(self->ct, Py_BuildValue("(OOO)", key, priority, data));
}


static struct PyMethodDef Treap_PyMethodDef[] = {
{"insert", (PyCFunction) Treap_insert, METH_VARARGS, NULL},
{"delete", (PyCFunction) Treap_delete, METH_VARARGS | METH_KEYWORDS, NULL},
{"search", (PyCFunction) Treap_search, METH_VARARGS | METH_KEYWORDS, NULL},
{NULL} /* Sentinel */
};

static PyMemberDef Treap_PyMemberDef[] = {
{"tree", T_OBJECT_EX, offsetof(Treap, tree), 0, "tree"},
{NULL} /* Sentinel */
};


static PyTypeObject TreapType = {
/* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "Treap",
/* tp_basicsize */ sizeof(Treap),
/* tp_itemsize */ 0,
/* tp_dealloc */ (destructor) Treap_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) Treap___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 */ Treap_PyMethodDef,
/* tp_members */ Treap_PyMemberDef,
/* tp_getset */ 0,
/* tp_base */ &CartesianTreeType,
/* tp_dict */ 0,
/* tp_descr_get */ 0,
/* tp_descr_set */ 0,
/* tp_dictoffset */ 0,
/* tp_init */ 0,
/* tp_alloc */ 0,
/* tp_new */ Treap___new__,
};

#endif
7 changes: 7 additions & 0 deletions pydatastructs/trees/_backend/cpp/trees.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "SplayTree.hpp"
#include "AVLTree.hpp"
#include "CartesianTree.hpp"
#include "Treap.hpp"

static struct PyModuleDef trees_struct = {
PyModuleDef_HEAD_INIT,
Expand Down Expand Up @@ -75,5 +76,11 @@ PyMODINIT_FUNC PyInit__trees(void) {
Py_INCREF(&CartesianTreeType);
PyModule_AddObject(trees, "CartesianTree", reinterpret_cast<PyObject*>(&CartesianTreeType));

if (PyType_Ready(&TreapType) < 0) {
return NULL;
}
Py_INCREF(&TreapType);
PyModule_AddObject(trees, "Treap", reinterpret_cast<PyObject*>(&TreapType));

return trees;
}
11 changes: 10 additions & 1 deletion pydatastructs/trees/binary_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -905,9 +905,18 @@ class Treap(CartesianTree):
.. [1] https://en.wikipedia.org/wiki/Treap
"""
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.Treap(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']
return ['__new__', 'insert']

def insert(self, key, data=None):
priority = random.random()
Expand Down
19 changes: 10 additions & 9 deletions pydatastructs/trees/tests/test_binary_trees.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ def test_AVLTree():
_test_AVLTree(backend=Backend.PYTHON)
def test_cpp_AVLTree():
_test_AVLTree(backend=Backend.CPP)
test_cpp_AVLTree()

def _test_BinaryIndexedTree(backend):

FT = BinaryIndexedTree
Expand Down Expand Up @@ -423,12 +423,6 @@ def _test_CartesianTree(backend):
tree.insert(8, 49, 8)
tree.insert(2, 99, 2)
# Explicit check for the redefined __str__ method of Cartesian Trees Class
assert str(tree) == \
("[(1, 3, 1, 3, 3), (2, 1, 6, 1, 9), "
"(None, 0, 9, 0, None), (4, 5, 11, 5, 5), "
"(None, 4, 14, 4, None), (6, 9, 17, 9, None), "
"(7, 7, 22, 7, 8), (None, 6, 42, 6, None), "
"(None, 8, 49, 8, None), (None, 2, 99, 2, None)]")

trav = BinaryTreeTraversal(tree, backend=backend)
in_order = trav.depth_first_search(order='in_order')
Expand Down Expand Up @@ -462,21 +456,28 @@ def test_CartesianTree():
def test_cpp_CartesianTree():
_test_CartesianTree(backend=Backend.CPP)

def test_Treap():
def _test_Treap(backend):

random.seed(0)
tree = Treap()
tree = Treap(backend=backend)
tree.insert(7, 7)
tree.insert(2, 2)
tree.insert(3, 3)
tree.insert(4, 4)
tree.insert(5, 5)
print(str(tree))
assert isinstance(tree.tree[0].priority, float)
tree.delete(1)
assert tree.search(1) is None
assert tree.search(2) == 1
assert tree.delete(1) is None

def test_Treap():
_test_Treap(Backend.PYTHON)

def test_cpp_Treap():
_test_Treap(Backend.CPP)

def _test_SelfBalancingBinaryTree(backend):
"""
https://github.com/codezonediitj/pydatastructs/issues/234
Expand Down
3 changes: 2 additions & 1 deletion pydatastructs/utils/_backend/cpp/TreeNode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ typedef struct {
long size;
long color;
bool isCartesianTreeNode;
long priority;
double priority;
} TreeNode;

static void TreeNode_dealloc(TreeNode *self) {
Expand Down Expand Up @@ -65,6 +65,7 @@ static struct PyMemberDef TreeNode_PyMemberDef[] = {
{"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"},
{"priority", T_DOUBLE, offsetof(TreeNode, priority), 0, "CartesianTreeNode's priority"},
{NULL},
};

Expand Down

0 comments on commit 35844a2

Please sign in to comment.