假设有一个树:
a
/ \
b c
/ \ / \
d e f g
涉及到的变量:root当前节点 、tmp 当前节点的前驱节点(极右)、prev前一个节点(99题用到 可以存前一个节点来比较val)
Morris遍历的优点:
空间复杂度为 O(1)
Morris遍历的规则:
-
无左子树 :访问
root,root向右走 -
有左子树:
-
找
tmp(左子树的极右节点) -
第一次到:
tmp.right指向root,root向左走 -
第二次到:
tmp.right恢复为null,访问root,root向右走
-
Morris遍历的实现:
a
/ \
b c
/ \ / \
d e f g
当前节点root依次经过a b d b e a c f c g
可以发现a b c(有左子树的节点)都经历了两次,d e f g(无左子树的节点)只经历了1次
前序遍历(a b d e c f g)就是取a b d b e a c f c g第一次经过的a b c和无子树的节点**{有1+无}**
中序遍历(d b e a f c g)就是取a b d b e a c f c g第二次经过的a b c和无子树的节点**{有2+无}**
Morris遍历的过程:
a
/ \
b c
/ \ / \
d e f g
一开始root=a;tmp=e,发现是有1,让tmp.right指向a,root=b;继续发现是有1,让d指向b,root=d,发现是无左子树,让root=root.right,发现是有2,断开d和b的指向关系、root=root.right。root变成了e,又变成了无的情况,让root变成a,再经历有2,断开和更新root.......
prev用于力扣第99题,存前一个节点,方便和当前节点root进行比较。
prev要有空和非空的比较,这样做可以方便一开始prev=d
leetcode99:
题目:
给你二叉搜索树的根节点 root ,该树中的 恰好 两个节点的值被错误地交换。请在不改变其结构的情况下,恢复这棵树。
代码:
java
class Solution {
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
//Morris遍历 空间复杂度O(1)
public void recoverTree(TreeNode root) {
TreeNode x=null;
TreeNode y=null;
TreeNode tmp=null;//前驱节点(极右)
TreeNode prev=null;//记录前一个结点
while (root!=null){
//找tmp
if(root.left!=null){//有左子树
tmp=root.left;
while (tmp.right!=null&&tmp.right!=root){
tmp=tmp.right;
}
if(tmp.right==null){//有1
tmp.right=root;
root=root.left;
}else{//有2
if(prev!=null&&prev.val>root.val){
x=root;
if(y==null){
y=prev;
}
}//交换
prev=root;
root=root.right;
tmp.right=null;
}
}else{//无左子树
if(prev!=null&&prev.val>root.val){
x=root;
if(y==null){
y=prev;
}
}//交换
prev=root;
root=root.right;
}
}
if(x!=null && y!=null) {
int t = x.val;
x.val = y.val;
y.val = t;
}
}
}