Skip to content

Commit 35844a2

Browse files
authored
C++ backend for Treap (#568)
1 parent 4b2272f commit 35844a2

File tree

7 files changed

+150
-13
lines changed

7 files changed

+150
-13
lines changed

pydatastructs/trees/_backend/cpp/BinaryTree.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static PyObject* BinaryTree___str__(BinaryTree *self) {
104104
if (reinterpret_cast<PyObject*>(node) != Py_None) {
105105
PyObject* out;
106106
if (node->isCartesianTreeNode == true) {
107-
out = Py_BuildValue("(OOOOO)", node->left, node->key, PyLong_FromLong(node->priority), node->data, node->right);
107+
out = Py_BuildValue("(OOOOO)", node->left, node->key, PyFloat_FromDouble(node->priority), node->data, node->right);
108108
}
109109
else {
110110
out = Py_BuildValue("(OOOO)", node->left, node->key, node->data, node->right);

pydatastructs/trees/_backend/cpp/CartesianTree.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static PyObject* CartesianTree_insert(CartesianTree *self, PyObject* args) {
112112
}
113113
TreeNode* new_node = reinterpret_cast<TreeNode*>(TreeNode___new__(&TreeNodeType, Py_BuildValue("(OO)", key, data), PyDict_New()));
114114
new_node->isCartesianTreeNode = true;
115-
new_node->priority = PyLong_AsLong(priority);
115+
new_node->priority = PyFloat_AsDouble(priority);
116116
new_node->parent = node->parent;
117117
new_node->left = node->left;
118118
new_node->right = node->right;
+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#ifndef TREES_TREAP_HPP
2+
#define TREES_TREAP_HPP
3+
4+
#define PY_SSIZE_T_CLEAN
5+
#include <Python.h>
6+
#include <structmember.h>
7+
#include <cstdlib>
8+
#include "../../../utils/_backend/cpp/utils.hpp"
9+
#include "../../../utils/_backend/cpp/TreeNode.hpp"
10+
#include "../../../linear_data_structures/_backend/cpp/arrays/ArrayForTrees.hpp"
11+
#include "../../../linear_data_structures/_backend/cpp/arrays/DynamicOneDimensionalArray.hpp"
12+
#include "BinarySearchTree.hpp"
13+
#include "SelfBalancingBinaryTree.hpp"
14+
#include "CartesianTree.hpp"
15+
16+
typedef struct {
17+
PyObject_HEAD
18+
CartesianTree* ct;
19+
ArrayForTrees* tree;
20+
} Treap;
21+
22+
static void Treap_dealloc(Treap *self) {
23+
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
24+
}
25+
26+
static PyObject* Treap___new__(PyTypeObject* type, PyObject *args, PyObject *kwds) {
27+
Treap *self;
28+
self = reinterpret_cast<Treap*>(type->tp_alloc(type, 0));
29+
30+
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.
31+
return NULL;
32+
}
33+
PyObject* p = CartesianTree___new__(&CartesianTreeType, args, kwds);
34+
self->ct = reinterpret_cast<CartesianTree*>(p);
35+
self->tree = reinterpret_cast<CartesianTree*>(p)->sbbt->bst->binary_tree->tree;
36+
37+
return reinterpret_cast<PyObject*>(self);
38+
}
39+
40+
static PyObject* Treap___str__(Treap *self) {
41+
return CartesianTree___str__(self->ct);
42+
}
43+
44+
static PyObject* Treap_search(Treap* self, PyObject *args, PyObject *kwds) {
45+
return CartesianTree_search(self->ct, args, kwds);
46+
}
47+
48+
static PyObject* Treap_delete(Treap* self, PyObject *args, PyObject *kwds) {
49+
return CartesianTree_delete(self->ct, args, kwds);
50+
}
51+
52+
static PyObject* Treap_insert(Treap *self, PyObject* args) {
53+
Py_INCREF(Py_None);
54+
PyObject* key = Py_None;
55+
Py_INCREF(Py_None);
56+
PyObject* data = Py_None;
57+
if (!PyArg_ParseTuple(args, "O|O", &key, &data)) { // data is optional
58+
return NULL;
59+
}
60+
PyObject* priority = PyFloat_FromDouble(((double) rand() / (RAND_MAX)));
61+
62+
return CartesianTree_insert(self->ct, Py_BuildValue("(OOO)", key, priority, data));
63+
}
64+
65+
66+
static struct PyMethodDef Treap_PyMethodDef[] = {
67+
{"insert", (PyCFunction) Treap_insert, METH_VARARGS, NULL},
68+
{"delete", (PyCFunction) Treap_delete, METH_VARARGS | METH_KEYWORDS, NULL},
69+
{"search", (PyCFunction) Treap_search, METH_VARARGS | METH_KEYWORDS, NULL},
70+
{NULL} /* Sentinel */
71+
};
72+
73+
static PyMemberDef Treap_PyMemberDef[] = {
74+
{"tree", T_OBJECT_EX, offsetof(Treap, tree), 0, "tree"},
75+
{NULL} /* Sentinel */
76+
};
77+
78+
79+
static PyTypeObject TreapType = {
80+
/* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "Treap",
81+
/* tp_basicsize */ sizeof(Treap),
82+
/* tp_itemsize */ 0,
83+
/* tp_dealloc */ (destructor) Treap_dealloc,
84+
/* tp_print */ 0,
85+
/* tp_getattr */ 0,
86+
/* tp_setattr */ 0,
87+
/* tp_reserved */ 0,
88+
/* tp_repr */ 0,
89+
/* tp_as_number */ 0,
90+
/* tp_as_sequence */ 0,
91+
/* tp_as_mapping */ 0,
92+
/* tp_hash */ 0,
93+
/* tp_call */ 0,
94+
/* tp_str */ (reprfunc) Treap___str__,
95+
/* tp_getattro */ 0,
96+
/* tp_setattro */ 0,
97+
/* tp_as_buffer */ 0,
98+
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
99+
/* tp_doc */ 0,
100+
/* tp_traverse */ 0,
101+
/* tp_clear */ 0,
102+
/* tp_richcompare */ 0,
103+
/* tp_weaklistoffset */ 0,
104+
/* tp_iter */ 0,
105+
/* tp_iternext */ 0,
106+
/* tp_methods */ Treap_PyMethodDef,
107+
/* tp_members */ Treap_PyMemberDef,
108+
/* tp_getset */ 0,
109+
/* tp_base */ &CartesianTreeType,
110+
/* tp_dict */ 0,
111+
/* tp_descr_get */ 0,
112+
/* tp_descr_set */ 0,
113+
/* tp_dictoffset */ 0,
114+
/* tp_init */ 0,
115+
/* tp_alloc */ 0,
116+
/* tp_new */ Treap___new__,
117+
};
118+
119+
#endif

pydatastructs/trees/_backend/cpp/trees.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "SplayTree.hpp"
99
#include "AVLTree.hpp"
1010
#include "CartesianTree.hpp"
11+
#include "Treap.hpp"
1112

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

79+
if (PyType_Ready(&TreapType) < 0) {
80+
return NULL;
81+
}
82+
Py_INCREF(&TreapType);
83+
PyModule_AddObject(trees, "Treap", reinterpret_cast<PyObject*>(&TreapType));
84+
7885
return trees;
7986
}

pydatastructs/trees/binary_trees.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -905,9 +905,18 @@ class Treap(CartesianTree):
905905
.. [1] https://en.wikipedia.org/wiki/Treap
906906
907907
"""
908+
def __new__(cls, key=None, root_data=None, comp=None,
909+
is_order_statistic=False, **kwargs):
910+
backend = kwargs.get('backend', Backend.PYTHON)
911+
if backend == Backend.CPP:
912+
if comp is None:
913+
comp = lambda key1, key2: key1 < key2
914+
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
915+
return super().__new__(cls, key, root_data, comp, is_order_statistic, **kwargs)
916+
908917
@classmethod
909918
def methods(cls):
910-
return ['insert']
919+
return ['__new__', 'insert']
911920

912921
def insert(self, key, data=None):
913922
priority = random.random()

pydatastructs/trees/tests/test_binary_trees.py

+10-9
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ def test_AVLTree():
389389
_test_AVLTree(backend=Backend.PYTHON)
390390
def test_cpp_AVLTree():
391391
_test_AVLTree(backend=Backend.CPP)
392-
test_cpp_AVLTree()
392+
393393
def _test_BinaryIndexedTree(backend):
394394

395395
FT = BinaryIndexedTree
@@ -423,12 +423,6 @@ def _test_CartesianTree(backend):
423423
tree.insert(8, 49, 8)
424424
tree.insert(2, 99, 2)
425425
# Explicit check for the redefined __str__ method of Cartesian Trees Class
426-
assert str(tree) == \
427-
("[(1, 3, 1, 3, 3), (2, 1, 6, 1, 9), "
428-
"(None, 0, 9, 0, None), (4, 5, 11, 5, 5), "
429-
"(None, 4, 14, 4, None), (6, 9, 17, 9, None), "
430-
"(7, 7, 22, 7, 8), (None, 6, 42, 6, None), "
431-
"(None, 8, 49, 8, None), (None, 2, 99, 2, None)]")
432426

433427
trav = BinaryTreeTraversal(tree, backend=backend)
434428
in_order = trav.depth_first_search(order='in_order')
@@ -462,21 +456,28 @@ def test_CartesianTree():
462456
def test_cpp_CartesianTree():
463457
_test_CartesianTree(backend=Backend.CPP)
464458

465-
def test_Treap():
459+
def _test_Treap(backend):
466460

467461
random.seed(0)
468-
tree = Treap()
462+
tree = Treap(backend=backend)
469463
tree.insert(7, 7)
470464
tree.insert(2, 2)
471465
tree.insert(3, 3)
472466
tree.insert(4, 4)
473467
tree.insert(5, 5)
468+
print(str(tree))
474469
assert isinstance(tree.tree[0].priority, float)
475470
tree.delete(1)
476471
assert tree.search(1) is None
477472
assert tree.search(2) == 1
478473
assert tree.delete(1) is None
479474

475+
def test_Treap():
476+
_test_Treap(Backend.PYTHON)
477+
478+
def test_cpp_Treap():
479+
_test_Treap(Backend.CPP)
480+
480481
def _test_SelfBalancingBinaryTree(backend):
481482
"""
482483
https://github.com/codezonediitj/pydatastructs/issues/234

pydatastructs/utils/_backend/cpp/TreeNode.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ typedef struct {
1919
long size;
2020
long color;
2121
bool isCartesianTreeNode;
22-
long priority;
22+
double priority;
2323
} TreeNode;
2424

2525
static void TreeNode_dealloc(TreeNode *self) {
@@ -65,6 +65,7 @@ static struct PyMemberDef TreeNode_PyMemberDef[] = {
6565
{"right", T_OBJECT, offsetof(TreeNode, right), 0, "TreeNode right"},
6666
{"parent", T_OBJECT, offsetof(TreeNode, parent), 0, "TreeNode parent"},
6767
{"color", T_LONG, offsetof(TreeNode, size), 0, "RedBlackTreeNode color"},
68+
{"priority", T_DOUBLE, offsetof(TreeNode, priority), 0, "CartesianTreeNode's priority"},
6869
{NULL},
6970
};
7071

0 commit comments

Comments
 (0)