对于树的遍历,无论是递归还是迭代,都是需要额外的空间,由系统记录访问节点压栈,或者自己压栈。而Morris遍历,通过利用节点中的空闲指针,空间复杂度可以做到O(1),且时间复杂度依旧不变O(N).
Morris遍历规则:
1.若该节点cur有左树,则找到左树最右节点Morrisright
(1)若Morrisright的右指针指向NULL,则让其指向cur,cur左移动。
(2)若Morris右指针指向cur,则让该右指针指向空,cur右移动。
2.若无左树,cur右移。
直到cur为空,整棵树遍历完毕,可得Morris序(cur所在节点轨迹)。1 2 4 2 5 1 3 6 3 7
有Morris序可发现规律
1.无左树的结点,只会出现1次,如结点4,5,6,7。
2.有左树的结点会出现两次,且在其第二次出现期间会把左树结点便利完成。如结点1,2,3.
void morri(node *root)
{
if(root==NULL)
return ;
node *cur = root;
node *morriright;
while(cur)
{
if(cur->left!=NULL)//有左树
{
morriright = cur->left;
while(morriright->right&&morriright->right!=cur)//找到左子树最右节点
{
morriright = morriright->right;
}
if(morriright->right==NULL)//为空
{
morriright->right = cur;//把其右指针指向当前cur节点
cur = cur->left;//cur往左移
}else//Morris节点不为空
{
morriright->right = NULL;//还原
cur = cur->right;//cur右移
}
}else{
cur = cur->right;//无左树则往右移
}
}
}
Morris下的前中后序遍历
1.前序与中序
由上面规律知,前序遍历即只出现一次的节点在第一次出现即打印,出现两次的结点也均在第一次打印。而中序遍历不同在于出现两次的结点在第二次出现才打印。
void morri(node *root)
{
if(root==NULL)
return ;
node *cur = root;
node *morriright;
while(cur)
{
if(cur->left!=NULL) {
morriright = cur->left;
while(morriright->right&&morriright->right!=cur)
{
morriright = morriright->right;
}
if(morriright->right==NULL)//第一次出现
{
//cout<<cur->val<<" ";
morriright->right = cur;
cur = cur->left;
}else//第二次出现
{
cout<<cur->val<<" ";
morriright->right = NULL;
cur = cur->right;
}
}else{
cout<<cur->val<<" ";
cur = cur->right;//无左树,只会出新一次的结点在此
}
}
}
2.后序
后序遍历在迭代中也是相对复杂的。如下图我们只4 5 2 6 7 3 1为后序遍历,则可知,需要倒序打印红线上的结点。对于倒序,则参考单链表倒序,打印完后再倒回来。
node* reverse(node *head)
{
node* pre = NULL;
node* next = NULL;
while(head)
{
next = head->right;
head->right = pre;
pre = head;
head = next;
}
return pre;
}
void printfreverse(node *head)
{
node *cur = reverse(head);
node *tmp = cur;
while(tmp)
{
cout<<tmp->val<<" ";
tmp = tmp->right;
}
reverse(cur);
}
void morri(node *root)
{
if(root==NULL)
return ;
node *cur = root;
node *morriright;
while(cur)
{
if(cur->left!=NULL)
{
morriright = cur->left;
while(morriright->right&&morriright->right!=cur)
{
morriright = morriright->right;
}
if(morriright->right==NULL)
{
morriright->right = cur;
cur = cur->left;
}else
{
morriright->right = NULL;
printfreverse(cur->left);
cur = cur->right;
}
}else{
cur = cur->right;
}
}
printfreverse(root);
}