【算法】莫里斯遍历

Morris遍历

我们熟知的树的遍历方法有递归法和迭代法,这两种所要用到的空间复杂度为O(n),莫里斯遍历(Morris)可以将空间复杂度将为O(1)。

本篇是本人对于LeetCode官方题解的记录,不用于任何商业领域,也不因此获取任何收益,如果需要转载,请标记出处,并不可用于商业领域,且需获得官方同意。

莫里斯算法主要有以下几个步骤

1.如果 x 无左孩子,先将 x 的值加入答案数组,再访问 x的右孩子,即 x = x.right 。
2.如果 x有左孩子,则找到 x 左子树上最右的节点(即左子树中序遍历的最后一个节点,x 在中序遍历中的前驱节点),我们记为predecessor。根据 predecessor 的右孩子是否为空,进行如下操作。

  • 如果 predecessor 的右孩子为空,则将其右孩子指向 x,然后访问 x 的左孩子,即 x=x.left。
  • 如果 predecessor 的右孩子不为空,则此时其右孩子指向 x,说明我们已经遍历完 x 的左子树,我们将 predecessor 的右孩子置空,将 x 的值加入答案数组,然后访问 x 的右孩子,即 x =x.right。

具体实现:

public class TreeNode {
	int val;
	TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
public List<Integer> inorderTraversal(TreeNode root) {
	List<Integer> ans = new ArrayList<>();
    TreeNode predecessor = null;
    while(root != null) {
        if (root.left != null) {
            // predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止
            predecessor = root.left;
            while (predecessor.right != null && predecessor.right != root) {
                predecessor = predecessor.right;
            }
            // 让 predecessor 的右指针指向 root,继续遍历左子树
            if (predecessor.right == null) {
                predecessor.right = root;
                root = root.left;
            }
            // 说明左子树已经访问完了,这次root是第二次访问到的,我们需要断开链接
            else {
                ans.add(root.val);
                predecessor.right = null;
                root = root.right;
            }
        } else {
            ans.add(root.val);
            root = root.right;
        }
    }
    return ans;
}

可以到94.二叉树的中序遍历试一试

你可能感兴趣的:(数据结构和算法,算法)