Skip to content

Commit b1016de

Browse files
committed
feat: Add Morris In-Order Traversal to BinaryTreeTraversal
- Implemented `morris_in_order_traversal` method in the C++ backend. - Exposed the method to Python via `PyMethodDef`. - Added unit tests for Morris Traversal in the test suite. - Verified compatibility with both Python and C++ backends.
1 parent f4c1677 commit b1016de

File tree

3 files changed

+89
-1
lines changed

3 files changed

+89
-1
lines changed

pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,47 @@ static PyObject* BinaryTreeTraversal__out_order(BinaryTreeTraversal* self, PyObj
171171
return visit;
172172
}
173173

174+
static PyObject* BinaryTreeTraversal_morris_in_order_traversal(BinaryTreeTraversal* self, PyObject *args) {
175+
PyObject* node = PyObject_GetItem(args, PyZero);
176+
if (node == Py_None) {
177+
node = self->tree->root_idx;
178+
}
179+
180+
PyObject* traversal = PyList_New(0);
181+
ArrayForTrees* tree = self->tree->tree;
182+
long current = PyLong_AsLong(node);
183+
184+
while (current != Py_None) {
185+
TreeNode* current_node = reinterpret_cast<TreeNode*>(tree->_one_dimensional_array->_data[current]);
186+
if (current_node->left == Py_None) {
187+
// If there's no left child, visit the current node
188+
PyList_Append(traversal, reinterpret_cast<PyObject*>(current_node));
189+
current = PyLong_AsLong(current_node->right);
190+
} else {
191+
// Find the in-order predecessor (rightmost node in the left subtree)
192+
long predecessor = PyLong_AsLong(current_node->left);
193+
TreeNode* predecessor_node = reinterpret_cast<TreeNode*>(tree->_one_dimensional_array->_data[predecessor]);
194+
while (predecessor_node->right != Py_None && predecessor_node->right != node) {
195+
predecessor = PyLong_AsLong(predecessor_node->right);
196+
predecessor_node = reinterpret_cast<TreeNode*>(tree->_one_dimensional_array->_data[predecessor]);
197+
}
198+
199+
if (predecessor_node->right == Py_None) {
200+
// Make the current node the right child of the predecessor
201+
predecessor_node->right = node;
202+
current = PyLong_AsLong(current_node->left);
203+
} else {
204+
// Revert the changes made to the tree
205+
predecessor_node->right = Py_None;
206+
PyList_Append(traversal, reinterpret_cast<PyObject*>(current_node));
207+
current = PyLong_AsLong(current_node->right);
208+
}
209+
}
210+
}
211+
212+
return traversal;
213+
}
214+
174215
static PyObject* BinaryTreeTraversal_depth_first_search(BinaryTreeTraversal* self, PyObject *args, PyObject *kwds) {
175216
Py_INCREF(Py_None);
176217
PyObject* node = Py_None;
@@ -242,12 +283,12 @@ static struct PyMethodDef BinaryTreeTraversal_PyMethodDef[] = {
242283
{"_in_order", (PyCFunction) BinaryTreeTraversal__in_order, METH_VARARGS, NULL},
243284
{"_out_order", (PyCFunction) BinaryTreeTraversal__out_order, METH_VARARGS, NULL},
244285
{"_post_order", (PyCFunction) BinaryTreeTraversal__post_order, METH_VARARGS, NULL},
286+
{"morris_in_order_traversal", (PyCFunction) BinaryTreeTraversal_morris_in_order_traversal, METH_VARARGS, NULL},
245287
{"depth_first_search", (PyCFunction) BinaryTreeTraversal_depth_first_search, METH_VARARGS | METH_KEYWORDS, NULL},
246288
{"breadth_first_search", (PyCFunction) BinaryTreeTraversal_breadth_first_search, METH_VARARGS | METH_KEYWORDS, NULL},
247289
{NULL}
248290
};
249291

250-
251292
static PyTypeObject BinaryTreeTraversalType = {
252293
/* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "BinaryTreeTraversal",
253294
/* tp_basicsize */ sizeof(BinaryTreeTraversal),

pydatastructs/trees/binary_trees.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,50 @@ def breadth_first_search(self, node=None, strategy='queue'):
17611761
q.append(tree[node].right)
17621762
return visit
17631763

1764+
def morris_in_order_traversal(self, node=None):
1765+
"""
1766+
Perform in-order traversal using Morris Traversal.
1767+
1768+
Parameters
1769+
==========
1770+
1771+
node : int
1772+
The index of the node from where the traversal has to be instantiated.
1773+
By default, set to, root index.
1774+
1775+
Returns
1776+
=======
1777+
1778+
list
1779+
Each element of the list is of type `TreeNode`.
1780+
"""
1781+
if node is None:
1782+
node = self.tree.root_idx
1783+
1784+
traversal = []
1785+
current = node
1786+
1787+
while current is not None:
1788+
if self.tree.tree[current].left is None:
1789+
traversal.append(self.tree.tree[current])
1790+
current = self.tree.tree[current].right
1791+
else:
1792+
predecessor = self.tree.tree[current].left
1793+
while (
1794+
self.tree.tree[predecessor].right is not None
1795+
and self.tree.tree[predecessor].right != current
1796+
):
1797+
predecessor = self.tree.tree[predecessor].right
1798+
1799+
if self.tree.tree[predecessor].right is None:
1800+
self.tree.tree[predecessor].right = current
1801+
current = self.tree.tree[current].left
1802+
else:
1803+
self.tree.tree[predecessor].right = None
1804+
traversal.append(self.tree.tree[current])
1805+
current = self.tree.tree[current].right
1806+
return traversal
1807+
17641808
class BinaryIndexedTree(object):
17651809
"""
17661810
Represents binary indexed trees

pydatastructs/trees/tests/test_binary_trees.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ def _test_BinaryTreeTraversal(backend):
151151
bfs = trav.breadth_first_search()
152152
assert [node.key for node in bfs] == ['F', 'B', 'G', 'A', 'D', 'I', 'C', 'E', 'H']
153153

154+
morris_in_order = trav.morris_in_order_traversal()
155+
assert [node.key for node in morris_in_order] == ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']
156+
154157
assert raises(NotImplementedError, lambda: trav.breadth_first_search(strategy='iddfs'))
155158
assert raises(NotImplementedError, lambda: trav.depth_first_search(order='in_out_order'))
156159
assert raises(TypeError, lambda: BTT(1))

0 commit comments

Comments
 (0)