一般来说,二叉树有两种遍历方式,一种方式是递归遍历,一种是基于栈的非递归方式。
- 1°递归遍历,有时间复杂度O(n)O(n)O(n),空间复杂度平均O(logn)O(logn)O(logn),最坏情况下O(n)O(n)O(n)
- 2°基于栈的非递归遍历,有时间复杂度O(n)O(n)O(n),空间复杂度O(h)O(h)O(h)
而有一种巧妙的方法可以在时间复杂度为O(n),空间复杂度为O(1)的情况下实现二叉树遍历。这种方法由 J. H. Morris 在 1979 年的论文「Traversing Binary Trees Simply and Cheaply」中首次提出,因此被称为 Morris 遍历。
一、先序遍历
算法
1.如果跟结点root的左孩子为空,则打印root结点,root结点迭代为root的右孩子结点(所以函数参数不要为了图快而引用传递)
否则,定义cur结点为根结点root左子树的最右下角的结点,接下来又有两种情况:
①cur结点的右孩子指针已经指向root时,将该指针置空,root结点迭代为root结点的右孩子
②cur结点的右孩子指针为空时,打印root结点值,将cur结点的右孩子指针指向root,root结点迭代为root结点的左孩子
2.重复过程1直至root结点迭代为NULL
代码实现
// Preorder traversal without recursion and without stack
void morrisTraversalPreorder(node* root)
{
while (root)
{
// If left child is null, print the current node data. Move to
// right child.
if (root->left == NULL)
{
cout<<root->data<<" ";
root = root->right;
}
else
{
// Find inorder predecessor
node* current = root->left;
while (current->right && current->right != root)
current = current->right;
// If the right child of inorder predecessor already points to
// this node
if (current->right == root)
{
current->right = NULL;
root = root->right;
}
// If right child doesn't point to this node, then print this
// node and make right child point to this node
else
{
cout<<root->data<<" ";
current->right = root;
root = root->left;
}
}
}
}
二、中序遍历
算法
1.初始化cur结点为root
2.当cur不空时,检查其是否有左孩子结点
3.如果cur无左孩子,打印cur,并将其cur迭代为cur的右孩子结点
如果cur有左孩子,找到cur左子树的最右下方的叶子结点,定义为mostright
此时又有两种情况
①mostright的右孩子指针为空,则让其指向cur,cur迭代为cur的左孩子结点
②mostright的右孩子指针指向cur时,将其置空,cur迭代为cur的右孩子结点
4.重复过程2,3,直至cur为null
代码实现
void Morris( Node* root)
{
Node *cur, *mostright;
if (root == NULL) return;
cur = root;
while (cur != NULL) {
if (cur->left_node == NULL) {
cout << cur->data << endl;
cur = cur->right_node;
}
else {
/* Find the previous of cur */
mostright = cur->left_node;
while (mostright->right_node != NULL && mostright->right_node != cur)
mostright = mostright->right_node;
/* Make cur as the right child of itsprevious */
if (mostright->right_node == NULL) {
mostright->right_node = cur;
cur = cur->left_node;
}
/* fix the right child of previous */
else {
mostright->right_node = NULL;
cout << cur->data << endl;
cur = cur->right_node;
}
}
}
}
三、后序遍历
算法
后序遍历较为复杂,这里直接贴出算法原文。

代码实现
暂无
参考:geeksforgeeks论坛与edpresso
本文介绍了二叉树的Morris遍历方法,包括先序、中序和后序遍历的具体算法及代码实现。Morris遍历能在O(1)的空间复杂度下完成遍历,是一种高效且实用的技术。
1153

被折叠的 条评论
为什么被折叠?



