二叉树的前序遍历之Morris

之前我们介绍了二叉树前序排序的两种方法,一种是递归,一种是迭代。这两种没有什么大的差别。今天我们带来了一种Morris遍历

 

Morris 遍历的核心思想是利用树的大量空闲指针,实现空间开销的极限缩减

 

其前序遍历规则总结如下:

1,新建临时树,令该节点为树的根;

2,如果当前根的左子树为空,将当前根放入数组,并将当前根的右子树更新为树的根;

3,如果当前根的左子树不为空,获取到当前根的左子树:

    3.1, 循环遍历当前根的左子树的所有右子树,获取到最后一个不等于根的右子树

    3.1, 如果获取到的右子树为空,将根节点放入数组,然后将根赋值给遍历获取到的右子树的右子树。

    3.2, 如果获取到的右子树不为空,将获取到的右子树的右子树删除,同时将根的右子树更新为树的根

 

重复步骤 2 和步骤 3,直到遍历结束。

 

 

看到这里如果有一点点懵的话就看一下下面的图,我会一步一步的将实现过程给画出来。

 

 

 

第一步,我们获取到树的根F,然后获取F的左子树,如果左子树为空,我们就将F放入数组,然后获取树的右子树更新为树的根。

这里左子树不为空,我们第一步拿到树的左子树B,然后遍历B的所有右子树,一直遍历到右子树为空并且右子树不等于当前根的情况,这里我们B本来就没有右子树,所以直接拿到B。

当B的右子树为空,我们将F放入数组。然后将F放入B的右子树。

根节点指向B

 

 

 第二步,我们获取到树的根 B,判断B的左子树,如果左子树为空,我们将就将B 放入数组,同时将根指向 F

 

 

 

第三步,我们获取到树的根F,判断F的左子树是否为空,这里树的左子树不为空,所以拿到树的左子树B ,然后遍历B的所有右子树,一直遍历到右子树为空并且右子树不等于根的情况。

这里B的右子树是等于根的,所以走恢复二叉树的逻辑,将B的右子树 清空,同时将根指向根的右子树 A

 

 

 第四步,我们获取到树的根A,判断A的左子树是否为空,这里树的左子树不为空,所以拿到树的左子树D,然后遍历D的所有右子树,一直遍历到右子树为空并且右子树不等于当前根的情况,这里我们的D本来就没有右子树,所以直接拿到D ,因为D的右子树为空,那么我们将根A放入到数组,将根A放入到D的右子树。根节点指向D

 

 

 第五步,我们获取到树的根D,判断D的左子树,如果D的左子树为空,那么将D放入数组,同时将根指向A

 

 

 第六步,我们获取到树的根A,判断A的左子树是否为空,这里A的左子树是不为空的,所以拿到A的左子树D,然后遍历D的所有右子树,一直到右子树为空并且右子树不等于根,这里D的右子树等于根,我们走恢复二叉树逻辑,将D的右子树A删除,然后将根指向A的右子树C

 

 

 第七步,我们获取到树的根C,判断C的左子树是否为空,这里C的左子树为空,那么将C放入数组,同时将根指向C的右子树,C的右子树为空遍历结束

 

 

 经过我们一步一步的拆解,是不是已经感觉这个排序也超级简单呢,现在上代码

public static void main(String[] args) {
    Solution solution = new Solution();
    TreeNode t = new TreeNode("F", new TreeNode("B",null,null), new TreeNode("A", new TreeNode("D",null,null), new TreeNode("C",null,null)));
    System.out.println(Morris_PreOrder(t));
}

public static List<String> Morris_PreOrder(TreeNode root) {
    List<String> res = new ArrayList<>();
    if(root == null){
        return res;
    }
    TreeNode cur = root;
    while(cur != null) {
        if(cur.left == null) {
            res.add(cur.val);
            cur = cur.right;
        } else {
            TreeNode tmp = cur.left;
            while(tmp.right != null && tmp.right != cur){
                tmp = tmp.right;
            }
            if(tmp.right == null) {
                res.add(cur.val); //输出当前节点
                tmp.right = cur;  //将当前根节点赋值给 最右子树的右子树
                cur = cur.left;
            } else {
                tmp.right = null;  //恢复二叉树
                cur = cur.right;
            }
        }
    }
    return res;
}

  

是春风, 是余晖, 是一道曙光, 是未来可期。

 

手敲不易,点个赞呗

 

posted @ 2021-07-09 15:50  博客小屋  阅读(106)  评论(0编辑  收藏  举报