[LeetCode 94 144 145] 二叉树前序、中序和后序遍历总结(python)

给定一个二叉树,返回它的前序、中序  和后序遍历。

示例:

输入: [1,null,2,3]
   1
    \
     2
    /
   3

输出: 

前序:[1,2,3]
中序:[1,3,2]
后序:[3,2,1]

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

 

本文使用三种方法来实现。

一、方法一 递归

首先使用递归算法,就像上面所说,非常简单,几行代码搞定。

前序遍历:

class Solution:
    def preorderTraversal(self, root):
        self.res = []
        self.dec(root)
        return self.res

    def dec(self,root):
        if root:
            self.res.append(root.val)
            self.dec(root.left)
            self.dec(root.right)

中序遍历:

class Solution:
    def inorderTraversal(self, root):
        self.res = []
        self.dec(root)
        return self.res

    def dec(self,root):
        if root:
            self.dec(root.left)
            self.res.append(root.val)
            self.dec(root.right)

后序遍历:

class Solution:
    def postorderTraversal(self, root):
        self.res = []
        self.dec(root)
        return self.res

    def dec(self,root):
        if root:
            self.dec(root.left)
            self.dec(root.right)
            self.res.append(root.val)

二、方法二 借助栈的迭代

对比上面三种遍历的递归算法代码,只是改变了遍历的顺序,很好理解。

下面是迭代算法。巧妙利用栈的特点,便能很好实现目的。

前序遍历:

class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        """
        搜索到最左边,节点依次放进栈,搜索的同时将遍历的节点值放入结果数组
        """
        stack = []
        res = []
        while root or stack:
            if root:
                res.append(root.val)
                stack.append(root)
                root = root.left
            else:
                root = stack.pop()
                root = root.right
        return res

中序遍历:

class Solution:
    def inorderTravelsal(self, root: TreeNode) -> List[int]:
        """
        搜索到最左边,节点依次放进栈,
        """
        stack, res = [], []
        while root or stack:
            if root:
                stack.append(root)
                root = root.left
            else:
                root = stack.pop()
                res.append(root.val)
                root = root.right
        return res

后序遍历:

class Solution:
    def postorderTravelsal(self, root: TreeNode) -> List[int]:
        """
        对前序遍历进行稍微改造,变成"根-右-左"的顺序进行遍历,将得到的列表进行反转,便得到了后序遍历
        """
        stack, res = [], []
        while root or stack:
            if root:
                res.append(root.val)
                stack.append(root)
                root = root.right
            else:
                root = stack.pop()
                root = root.left
        return res[::-1]

 

三、方法三 Morris遍历算法

对于x节点,如果有左子树
    找到左子树的最右节点,为x的前驱节点 predecessor,根据 predecessor 的右节点是否存在,
    1 右节点为空,则右指向x,并访问x的左节点,x = x.left
    2 右节点不为空,则说明左子树已经访问完了,结果集中添加x,断开链接,并访问x的右子树,x = x.right
否则
    将x添加到结果集中,在访问x的右孩子,即 x = x.left

动画

前序遍历:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        TreeNode predecessor;
        while (root != null) {
            if (root.left != null) {
                predecessor = root.left;
                while (predecessor.right != null && predecessor.right != root) {
                    predecessor = predecessor.right;
                }
                if (predecessor.right == null) {
                    res.add(root.val);
                    predecessor.right = root;
                    root = root.left;
                } else {
                    predecessor.right = null;
                    root = root.right;
                }
            } else {
                res.add(root.val);
                root = root.right;
            }
        }
        return res;
    }
}

中序遍历

public class Solution {
    
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        TreeNode predecessor = null;

        while (root != null) {
            if (root.left != null) {
                predecessor = root.left;
                // predecessor不为null,并且前驱的右不是root
                while (predecessor.right != null && predecessor.right != root) {
                    predecessor = predecessor.right;
                }
                // 让 predecessor 的右指针指向root,继续遍历子树
                if (predecessor.right == null) {
                    predecessor.right = root;
                    root = root.left;
                } // 说明左子树已经访问完了,需要断开链接
                else {
                    res.add(root.val);
                    predecessor.right = null;
                    root = root.right;
                }
            }
            // 没有左孩子,则直接访问右孩子
            else {
                res.add(root.val);
                root = root.right;
            }
        }
        return res;
    }
}

后序遍历:

public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        TreeNode predecessor;
        while (root != null) {
            predecessor = root.right;
            if (root.right != null) {
                while (predecessor.left != null && predecessor.left != root) {
                    predecessor = predecessor.left;
                }
                if (predecessor.left == null) {
                    res.add(root.val);
                    predecessor.left = root;
                    root = root.right;
                } else {
                    predecessor.left = null;
                    root = root.left;
                }
            } else {
                res.add(root.val);
                root = root.left;
            }
        }
        Collections.reverse(res);
        return res;
    }
}

 

-------------------------------------------------------------------------------------------------------------------------------------

更多题目包括leetcode、牛客网、各种排序算法解法参见个人GitHub,持续更新中,欢迎star ~~

https://github.com/PemLer/Journey_of_leetcode

-------------------------------------------------------------------------------------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值