diff --git a/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp b/pydatastructs/trees/_backend/cpp/BinaryTreeTraversal.hpp index b430706f7..a39572d84 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(BinaryTreeTraversal* self, PyObject *args) { + PyObject* node = NULL; + if (!PyArg_ParseTuple(args, "|O", &node)) return NULL; + + if (node == NULL) node = self->tree->root_idx; + + PyObject* visit = PyList_New(0); + ArrayForTrees* tree = self->tree->tree; + PyObject* current = node; + + if (current == Py_None || self->tree->size == 0) return visit; + + while (current != Py_None) { + TreeNode* curr_node = reinterpret_cast(tree->_one_dimensional_array->_data[PyLong_AsLong(current)]); + + if (curr_node->left == Py_None) { + PyList_Append(visit, reinterpret_cast(curr_node)); + current = curr_node->right; + } else { + PyObject* pre_obj = curr_node->left; + TreeNode* pre_node = reinterpret_cast(tree->_one_dimensional_array->_data[PyLong_AsLong(pre_obj)]); + + while (pre_node->right != Py_None && pre_node->right != current) { + pre_obj = pre_node->right; + pre_node = reinterpret_cast(tree->_one_dimensional_array->_data[PyLong_AsLong(pre_obj)]); + } + + if (pre_node->right == Py_None) { + pre_node->right = current; + current = curr_node->left; + } else { + pre_node->right = Py_None; + PyList_Append(visit, reinterpret_cast(curr_node)); + current = curr_node->right; + } + } + } + + return visit; +} + static PyObject* BinaryTreeTraversal_depth_first_search(BinaryTreeTraversal* self, PyObject *args, PyObject *kwds) { Py_INCREF(Py_None); PyObject* node = Py_None; @@ -242,6 +283,7 @@ 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", (PyCFunction) BinaryTreeTraversal_morris_in_order, 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} diff --git a/pydatastructs/trees/binary_trees.py b/pydatastructs/trees/binary_trees.py index 4dc1fc3c8..2cfa5093c 100644 --- a/pydatastructs/trees/binary_trees.py +++ b/pydatastructs/trees/binary_trees.py @@ -1622,6 +1622,36 @@ def __new__(cls, tree, **kwargs): obj.tree = tree return obj + def morris_in_order(self, node=None): + """ + Implements Morris in-order traversal for the binary tree. + Returns + ------- + list + The list of nodes in in-order. + """ + if node is None: + node = self.tree.root_idx + + result = [] + current = node + while current is not None: + if self.tree.tree[current].left is None: + result.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 + result.append(self.tree.tree[current]) + current = self.tree.tree[current].right + return result + def _pre_order(self, node): """ Utility method for computing pre-order diff --git a/pydatastructs/trees/tests/test_binary_trees.py b/pydatastructs/trees/tests/test_binary_trees.py index 826100b78..05cbff20a 100644 --- a/pydatastructs/trees/tests/test_binary_trees.py +++ b/pydatastructs/trees/tests/test_binary_trees.py @@ -142,6 +142,9 @@ def _test_BinaryTreeTraversal(backend): ino = trav.depth_first_search() assert [node.key for node in ino] == ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] + morris_ino = trav.morris_in_order() + assert [node.key for node in morris_ino] == ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'] + out = trav.depth_first_search(order='out_order') assert [node.key for node in out] == ['I', 'H', 'G', 'F', 'E', 'D', 'C', 'B', 'A']