Skip to content

Commit 3cef009

Browse files
committed
C++ backend for AVL trees, till insert()
1 parent 4c6c935 commit 3cef009

File tree

3 files changed

+306
-1
lines changed

3 files changed

+306
-1
lines changed
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
#ifndef TREES_AVLTREE_HPP
2+
#define TREES_AVLTREE_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+
15+
typedef struct {
16+
PyObject_HEAD
17+
SelfBalancingBinaryTree* sbbt;
18+
ArrayForTrees* tree;
19+
} AVLTree;
20+
21+
static void AVLTree_dealloc(AVLTree *self) {
22+
Py_TYPE(self)->tp_free(reinterpret_cast<PyObject*>(self));
23+
}
24+
25+
static PyObject* AVLTree___new__(PyTypeObject* type, PyObject *args, PyObject *kwds) {
26+
AVLTree *self;
27+
self = reinterpret_cast<AVLTree*>(type->tp_alloc(type, 0));
28+
29+
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.
30+
return NULL;
31+
}
32+
PyObject* p = SelfBalancingBinaryTree___new__(&SelfBalancingBinaryTreeType, args, kwds);
33+
self->sbbt = reinterpret_cast<SelfBalancingBinaryTree*>(p);
34+
self->tree = reinterpret_cast<SelfBalancingBinaryTree*>(p)->bst->binary_tree->tree;
35+
36+
return reinterpret_cast<PyObject*>(self);
37+
}
38+
39+
static PyObject* AVLTree___str__(AVLTree *self) {
40+
return BinarySearchTree___str__(self->sbbt->bst);
41+
}
42+
43+
static PyObject* AVLTree_search(AVLTree* self, PyObject *args, PyObject *kwds) {
44+
return BinarySearchTree_search(self->sbbt->bst, args, kwds);
45+
}
46+
47+
static long AVLTree_left_height(AVLTree* self, PyObject *args) {
48+
TreeNode* node = reinterpret_cast<TreeNode*>(PyObject_GetItem(args, PyZero));
49+
if (node->left != Py_None) {
50+
BinaryTree* bt = self->sbbt->bst->binary_tree;
51+
return reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node->left)])->height;
52+
}
53+
else{
54+
return (-1);
55+
}
56+
}
57+
58+
static long AVLTree_right_height(AVLTree* self, PyObject *args) {
59+
TreeNode* node = reinterpret_cast<TreeNode*>(PyObject_GetItem(args, PyZero));
60+
if (node->right != Py_None) {
61+
BinaryTree* bt = self->sbbt->bst->binary_tree;
62+
return reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(node->right)])->height;
63+
}
64+
else{
65+
return -1;
66+
}
67+
}
68+
69+
static long AVLTree_balance_factor(AVLTree* self, PyObject *args) {
70+
TreeNode* node = reinterpret_cast<TreeNode*>(PyObject_GetItem(args, PyZero));
71+
return AVLTree_left_height(self, Py_BuildValue("(O)", node)) - AVLTree_right_height(self, Py_BuildValue("(O)", node));
72+
}
73+
74+
static PyObject* AVLTree__right_rotate(AVLTree* self, PyObject *args) {
75+
PyObject* j = PyObject_GetItem(args, PyZero);
76+
PyObject* k = PyObject_GetItem(args, PyOne);
77+
BinaryTree* bt = self->sbbt->bst->binary_tree;
78+
SelfBalancingBinaryTree__right_rotate(self->sbbt, Py_BuildValue("(OO)", j, k));
79+
80+
long lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
81+
long rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
82+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->height = std::max(lh, rh) + 1;
83+
84+
if (bt->is_order_statistic == true) {
85+
long ls = BinarySearchTree_left_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
86+
long rs = BinarySearchTree_right_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
87+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->size = ls + rs + 1;
88+
}
89+
90+
Py_RETURN_NONE;
91+
}
92+
93+
static PyObject* AVLTree__left_right_rotate(AVLTree* self, PyObject *args) {
94+
PyObject* j = PyObject_GetItem(args, PyZero);
95+
PyObject* k = PyObject_GetItem(args, PyOne);
96+
BinaryTree* bt = self->sbbt->bst->binary_tree;
97+
SelfBalancingBinaryTree__left_right_rotate(self->sbbt, Py_BuildValue("(OO)", j, k));
98+
99+
long lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
100+
long rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
101+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->height = std::max(lh, rh) + 1;
102+
103+
lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
104+
rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
105+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->height = std::max(lh, rh) + 1;
106+
107+
if (bt->is_order_statistic == true) {
108+
long ls = BinarySearchTree_left_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
109+
long rs = BinarySearchTree_right_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
110+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->size = ls + rs + 1;
111+
112+
ls = BinarySearchTree_left_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
113+
rs = BinarySearchTree_right_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
114+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->size = ls + rs + 1;
115+
}
116+
117+
Py_RETURN_NONE;
118+
}
119+
120+
static PyObject* AVLTree__right_left_rotate(AVLTree* self, PyObject *args) {
121+
PyObject* j = PyObject_GetItem(args, PyZero);
122+
PyObject* k = PyObject_GetItem(args, PyOne);
123+
BinaryTree* bt = self->sbbt->bst->binary_tree;
124+
SelfBalancingBinaryTree__right_left_rotate(self->sbbt, Py_BuildValue("(OO)", j, k));
125+
126+
long lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
127+
long rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
128+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->height = std::max(lh, rh) + 1;
129+
130+
lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
131+
rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
132+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->height = std::max(lh, rh) + 1;
133+
134+
if (bt->is_order_statistic == true) {
135+
long ls = BinarySearchTree_left_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
136+
long rs = BinarySearchTree_right_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
137+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->size = ls + rs + 1;
138+
139+
ls = BinarySearchTree_left_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
140+
rs = BinarySearchTree_right_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
141+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->size = ls + rs + 1;
142+
}
143+
144+
Py_RETURN_NONE;
145+
}
146+
147+
static PyObject* AVLTree__left_rotate(AVLTree* self, PyObject *args) {
148+
PyObject* j = PyObject_GetItem(args, PyZero);
149+
PyObject* k = PyObject_GetItem(args, PyOne);
150+
BinaryTree* bt = self->sbbt->bst->binary_tree;
151+
SelfBalancingBinaryTree__left_rotate(self->sbbt, Py_BuildValue("(OO)", j, k));
152+
153+
long lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
154+
long rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
155+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->height = std::max(lh, rh) + 1;
156+
157+
lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
158+
rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)]));
159+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(k)])->height = std::max(lh, rh) + 1;
160+
161+
if (bt->is_order_statistic == true) {
162+
long ls = BinarySearchTree_left_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
163+
long rs = BinarySearchTree_right_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)]));
164+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(j)])->size = ls + rs + 1;
165+
}
166+
167+
Py_RETURN_NONE;
168+
}
169+
170+
static PyObject* AVLTree__balance_insertion(AVLTree* self, PyObject *args) {
171+
PyObject* curr = PyObject_GetItem(args, PyZero);
172+
PyObject* last = PyObject_GetItem(args, PyOne);
173+
BinaryTree* bt = self->sbbt->bst->binary_tree;
174+
175+
PyObject* walk = last;
176+
std::queue<PyObject*> path;
177+
path.push(curr);
178+
path.push(last);
179+
180+
while (walk != Py_None) {
181+
long lh = AVLTree_left_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)]));
182+
long rh = AVLTree_right_height(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)]));
183+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->height = std::max(lh, rh) + 1;
184+
185+
if (bt->is_order_statistic == true) {
186+
long ls = BinarySearchTree_left_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)]));
187+
long rs = BinarySearchTree_right_size(self->sbbt->bst, reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)]));
188+
reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->size = ls + rs + 1;
189+
}
190+
191+
last = path.front();
192+
path.pop();
193+
PyObject* last2last = path.front();
194+
path.pop();
195+
long bf = AVLTree_balance_factor(self, Py_BuildValue("(O)", bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)]));
196+
if (bf != 1 && bf != 0 && bf != -1) {
197+
PyObject* l = reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->left;
198+
if (l != Py_None && l == last && reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(l)])->left == last2last) {
199+
AVLTree__right_rotate(self, Py_BuildValue("(OO)", walk, last));
200+
}
201+
202+
PyObject* r = reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->right;
203+
if (r != Py_None && r == last && reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(r)])->right == last2last) {
204+
AVLTree__left_rotate(self, Py_BuildValue("(OO)", walk, last));
205+
}
206+
207+
if (l != Py_None && l == last && reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(l)])->right == last2last) {
208+
AVLTree__left_right_rotate(self, Py_BuildValue("(OO)", walk, last));
209+
}
210+
211+
if (r != Py_None && r == last && reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(r)])->left == last2last) {
212+
AVLTree__right_left_rotate(self, Py_BuildValue("(OO)", walk, last));
213+
}
214+
}
215+
path.push(walk);
216+
path.push(last);
217+
walk = reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[PyLong_AsLong(walk)])->parent;
218+
}
219+
220+
Py_RETURN_NONE;
221+
}
222+
223+
static PyObject* AVLTree_insert(AVLTree* self, PyObject *args) {
224+
Py_INCREF(Py_None);
225+
PyObject* key = Py_None;
226+
Py_INCREF(Py_None);
227+
PyObject* data = Py_None;
228+
if (!PyArg_ParseTuple(args, "O|O", &key, &data)) { // data is optional
229+
return NULL;
230+
}
231+
SelfBalancingBinaryTree_insert(self->sbbt, Py_BuildValue("(OO)", key, data));
232+
long s = self->sbbt->bst->binary_tree->size - 1;
233+
AVLTree__balance_insertion(self, Py_BuildValue("(OO)", PyLong_FromLong(s), reinterpret_cast<TreeNode*>(bt->tree->_one_dimensional_array->_data[s])->parent));
234+
235+
Py_RETURN_NONE;
236+
}
237+
238+
static struct PyMethodDef AVLTree_PyMethodDef[] = {
239+
{"search", (PyCFunction) AVLTree_search, METH_VARARGS | METH_KEYWORDS, NULL},
240+
{NULL}
241+
};
242+
243+
static PyMemberDef AVLTree_PyMemberDef[] = {
244+
{"tree", T_OBJECT_EX, offsetof(AVLTree, tree), 0, "tree"},
245+
{NULL} /* Sentinel */
246+
};
247+
248+
249+
static PyTypeObject AVLTreeType = {
250+
/* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "AVLTree",
251+
/* tp_basicsize */ sizeof(AVLTree),
252+
/* tp_itemsize */ 0,
253+
/* tp_dealloc */ (destructor) AVLTree_dealloc,
254+
/* tp_print */ 0,
255+
/* tp_getattr */ 0,
256+
/* tp_setattr */ 0,
257+
/* tp_reserved */ 0,
258+
/* tp_repr */ 0,
259+
/* tp_as_number */ 0,
260+
/* tp_as_sequence */ 0,
261+
/* tp_as_mapping */ 0,
262+
/* tp_hash */ 0,
263+
/* tp_call */ 0,
264+
/* tp_str */ (reprfunc) AVLTree___str__,
265+
/* tp_getattro */ 0,
266+
/* tp_setattro */ 0,
267+
/* tp_as_buffer */ 0,
268+
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
269+
/* tp_doc */ 0,
270+
/* tp_traverse */ 0,
271+
/* tp_clear */ 0,
272+
/* tp_richcompare */ 0,
273+
/* tp_weaklistoffset */ 0,
274+
/* tp_iter */ 0,
275+
/* tp_iternext */ 0,
276+
/* tp_methods */ AVLTree_PyMethodDef,
277+
/* tp_members */ AVLTree_PyMemberDef,
278+
/* tp_getset */ 0,
279+
/* tp_base */ &SelfBalancingBinaryTreeType,
280+
/* tp_dict */ 0,
281+
/* tp_descr_get */ 0,
282+
/* tp_descr_set */ 0,
283+
/* tp_dictoffset */ 0,
284+
/* tp_init */ 0,
285+
/* tp_alloc */ 0,
286+
/* tp_new */ AVLTree___new__,
287+
};
288+
289+
#endif

pydatastructs/trees/_backend/cpp/trees.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "RedBlackTree.hpp"
77
#include "BinaryIndexedTree.hpp"
88
#include "SplayTree.hpp"
9+
#include "AVLTree.hpp"
910

1011
static struct PyModuleDef trees_struct = {
1112
PyModuleDef_HEAD_INIT,
@@ -61,5 +62,11 @@ PyMODINIT_FUNC PyInit__trees(void) {
6162
Py_INCREF(&SplayTreeType);
6263
PyModule_AddObject(trees, "SplayTree", reinterpret_cast<PyObject*>(&SplayTreeType));
6364

65+
if (PyType_Ready(&AVLTreeType) < 0) {
66+
return NULL;
67+
}
68+
Py_INCREF(&AVLTreeType);
69+
PyModule_AddObject(trees, "AVLTree", reinterpret_cast<PyObject*>(&AVLTreeType));
70+
6471
return trees;
6572
}

pydatastructs/trees/binary_trees.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -921,9 +921,18 @@ class AVLTree(SelfBalancingBinaryTree):
921921
pydatastructs.trees.binary_trees.BinaryTree
922922
"""
923923

924+
def __new__(cls, key=None, root_data=None, comp=None,
925+
is_order_statistic=False, **kwargs):
926+
backend = kwargs.get('backend', Backend.PYTHON)
927+
if backend == Backend.CPP:
928+
if comp is None:
929+
comp = lambda key1, key2: key1 < key2
930+
return _trees.AVLTree(key, root_data, comp, is_order_statistic, **kwargs) # If any argument is not given, then it is passed as None, except for comp
931+
return super().__new__(cls, key, root_data, comp, is_order_statistic, **kwargs)
932+
924933
@classmethod
925934
def methods(cls):
926-
return ['insert', 'delete']
935+
return ['__new__', 'insert', 'delete']
927936

928937
left_height = lambda self, node: self.tree[node.left].height \
929938
if node.left is not None else -1

0 commit comments

Comments
 (0)