144.二叉树的前序遍历

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

 

示例 1:


输入:root = [1,null,2,3]
输出:[1,2,3]
示例 2:

输入:root = []
输出:[]
示例 3:

输入:root = [1]
输出:[1]

解法一:递归求解,按照当前节点,然后前节点,后节点

public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        preorder(root,res);
        return res;
    }
    void preorder(TreeNode root,List<Integer> res) {
        if(root==null)
            return ;
        res.add(root.val);
        preorder(root.left,res);
        preorder(root.right,res);
    }

解法二:递归本身就是一种隐式迭代,可以转化成迭代形式,只需要简单修改输出的顺序

 public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        Deque<TreeNode> stk = new LinkedList<TreeNode>();
         while (root != null || !stk.isEmpty()) {
            while (root != null) {
                res.add(root.val);
                stk.push(root);
                root = root.left;
            }
            if (!stk.isEmpty()) {
                root = stk.pop();
                root = root.right;
            }

        }
        return res;
    }

解法三:

有一种巧妙的方法可以在线性时间内,只占用常数空间来实现前序遍历。这种方法由 J. H. Morris 在 1979 年的论文「Traversing Binary Trees Simply and Cheaply」中首次提出,因此被称为 Morris 遍历。

Morris 遍历的核心思想是利用树的大量空闲指针,实现空间开销的极限缩减。其前序遍历规则总结如下:

新建临时节点,令该节点为 root;

如果当前节点的左子节点为空,将当前节点加入答案,并遍历当前节点的右子节点;

如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点:

如果前驱节点的右子节点为空,将前驱节点的右子节点设置为当前节点。然后将当前节点加入答案,并将前驱节点的右子节点更新为当前节点。当前节点更新为当前节点的左子节点。

如果前驱节点的右子节点为当前节点,将它的右子节点重新设为空。当前节点更新为当前节点的右子节点。

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

这样我们利用 Morris 遍历的方法,前序遍历该二叉树,即可实现线性时间与常数空间的遍历。

 

posted @ 2021-06-07 21:46  zhustarstar  阅读(68)  评论(0编辑  收藏  举报