diff --git a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index b430706f..df8bf443 100644 --- a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp +++ b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp @@ -171,6 +171,47 @@ static PyObject* BinaryTreeTraversal__out_order(BinaryTreeTraversal* self, PyObj return visit; } +static PyObject* BinaryTreeTraversal_morris_in_order_traversal(BinaryTreeTraversal* self, PyObject *args) { + PyObject* node = PyObject_GetItem(args, PyZero); + if (node == Py_None) { + node = self->tree->root_idx; + } + + PyObject* traversal = PyList_New(0); + ArrayForTrees* tree = self->tree->tree; + long current = PyLong_AsLong(node); + + while (current != Py_None) { + TreeNode* current_node = reinterpret_cast(tree->_one_dimensional_array->_data[current]); + if (current_node->left == Py_None) { + // If there's no left child, visit the current node + PyList_Append(traversal, reinterpret_cast(current_node)); + current = PyLong_AsLong(current_node->right); + } else { + // Find the in-order predecessor (rightmost node in the left subtree) + long predecessor = PyLong_AsLong(current_node->left); + TreeNode* predecessor_node = reinterpret_cast(tree->_one_dimensional_array->_data[predecessor]); + while (predecessor_node->right != Py_None && predecessor_node->right != node) { + predecessor = PyLong_AsLong(predecessor_node->right); + predecessor_node = reinterpret_cast(tree->_one_dimensional_array->_data[predecessor]); + } + + if (predecessor_node->right == Py_None) { + // Make the current node the right child of the predecessor + predecessor_node->right = node; + current = PyLong_AsLong(current_node->left); + } else { + // Revert the changes made to the tree + predecessor_node->right = Py_None; + PyList_Append(traversal, reinterpret_cast(current_node)); + current = PyLong_AsLong(current_node->right); + } + } + } + + return traversal; +} + static PyObject* BinaryTreeTraversal_depth_first_search(BinaryTreeTraversal* self, PyObject *args, PyObject *kwds) { Py_INCREF(Py_None); PyObject* node = Py_None; @@ -242,12 +283,12 @@ static struct PyMethodDef BinaryTreeTraversal_PyMethodDef[] = { {"_in_order", (PyCFunction) BinaryTreeTraversal__in_order, METH_VARARGS, NULL}, {"_out_order", (PyCFunction) BinaryTreeTraversal__out_order, METH_VARARGS, NULL}, {"_post_order", (PyCFunction) BinaryTreeTraversal__post_order, METH_VARARGS, NULL}, + {"morris_in_order_traversal", (PyCFunction) BinaryTreeTraversal_morris_in_order_traversal, METH_VARARGS, NULL}, {"depth_first_search", (PyCFunction) BinaryTreeTraversal_depth_first_search, METH_VARARGS | METH_KEYWORDS, NULL}, {"breadth_first_search", (PyCFunction) BinaryTreeTraversal_breadth_first_search, METH_VARARGS | METH_KEYWORDS, NULL}, {NULL} }; - static PyTypeObject BinaryTreeTraversalType = { /* tp_name */ PyVarObject_HEAD_INIT(NULL, 0) "BinaryTreeTraversal", /* tp_basicsize */ sizeof(BinaryTreeTraversal), diff --git a/pydatastructs/trees/binary_trees.py b/pydatastructs/trees/binary_trees.py index 4dc1fc3c..f422bc8a 100644 --- a/pydatastructs/trees/binary_trees.py +++ b/pydatastructs/trees/binary_trees.py @@ -1761,6 +1761,50 @@ def breadth_first_search(self, node=None, strategy='queue'): q.append(tree[node].right) return visit + def morris_in_order_traversal(self, node=None): + """ + Perform in-order traversal using Morris Traversal. + + Parameters + ========== + + node : int + The index of the node from where the traversal has to be instantiated. + By default, set to, root index. + + Returns + ======= + + list + Each element of the list is of type `TreeNode`. + """ + if node is None: + node = self.tree.root_idx + + traversal = [] + current = node + + while current is not None: + if self.tree.tree[current].left is None: + traversal.append(self.tree.tree[current]) + current = self.tree.tree[current].right + else: + predecessor = self.tree.tree[current].left + while ( + self.tree.tree[predecessor].right is not None + and self.tree.tree[predecessor].right != current + ): + predecessor = self.tree.tree[predecessor].right + + if self.tree.tree[predecessor].right is None: + self.tree.tree[predecessor].right = current + current = self.tree.tree[current].left + else: + self.tree.tree[predecessor].right = None + traversal.append(self.tree.tree[current]) + current = self.tree.tree[current].right + return traversal + class BinaryIndexedTree(object): """ Represents binary indexed trees diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 826100b7..0eeec149 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -151,6 +151,9 @@ def _test_BinaryTreeTraversal(backend): bfs = trav.breadth_first_search() assert [node.key for node in bfs] == ['F', 'B', 'G', 'A', 'D', 'I', 'C', 'E', 'H'] + morris_in_order = trav.morris_in_order_traversal() + assert [node.key for node in morris_in_order] == ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] + assert raises(NotImplementedError, lambda: trav.breadth_first_search(strategy='iddfs')) assert raises(NotImplementedError, lambda: trav.depth_first_search(order='in_out_order')) assert raises(TypeError, lambda: BTT(1))