二叉树的中序遍历,力扣

目录

前序遍历:

后序遍历:

题目地址:

题目:

解题方法:

解题分析:

解题思路:

代码实现:

注:

代码实现(递归):

代码实现(迭代):



前序遍历:

二叉树的前序遍历,力扣-CSDN博客

后序遍历:

二叉树的后序遍历,力扣-CSDN博客


题目地址:

94. 二叉树的中序遍历 - 力扣(LeetCode)

难度:简单

今天刷二叉树的中序遍历,大家有兴趣可以点上看看题目要求,试着做一下

题目:

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

我们直接看题解吧:

解题方法:

方法1,递归

方法2,迭代

方法3,Morris(空间复杂度(1))

解题分析:

中序遍历顺序:左子树->根节点->右子树(即左根右)

递归方法通俗易懂,但效率低,迭代方法,效率虽高,但不易理解,

因此这里着重讲一下Morris方法。

解题思路:

首先

     · 创建集合res 用于存储遍历的节点值

     ·创建prec作为临时节点

接着 循环遍历部分:

   设当前遍历节点为x

   a. 若x无左孩子,将x的值放入答案数组,接着访问x右孩子,即x=x.right。

   b. 若x有左孩子,则找到该左子树中最右的节点记为prec。

      · 若prec的右孩子为空,则将右孩子指向x, 接着访问x左孩子即x=x.left

      ·若prec的右孩子不为空,则将右孩子指向x,此时说明已遍历完x的左子树,则将prec的右孩子置空,将x的值加入答案数组,然后访问x的右孩子即x=x.right

   c. 重复上述操作,直至访问完整棵树。

注:左子树中最右的节点 ,即左子树中序遍历的最后一个节点

 具体可结合题解-->  :94. 二叉树的中序遍历 题解

代码实现:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>(); //创建集合存储节点的值
        TreeNode predecessor = null;   //创建predxessor节点,并置空

        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;
                }
                // 说明左子树已经访问完了,我们需要断开链接
                else {
                    res.add(root.val);
                    predecessor.right = null;
                    root = root.right;
                }
            }
            // 如果没有左孩子,则直接访问右孩子
            else {
                res.add(root.val);
                root = root.right;
            }
        }
        return res;
    }
}

注:

其实整个过程我们就多做一步:假设当前遍历到的节点为 x,

将 x 的左子树中最右边的 节点 的右孩子指向 x,这样在左子树遍历完成后 我们通过这个指向走回了 x,且能通过这个指向知晓我们已经遍历完成了左子树,而不用再通过栈来维护,省去了栈的空间复杂度。

代码实现(递归):

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
         //创建集合存储遍历的节点值
        List<Integer> res = new ArrayList<Integer>();
        inorder(root, res);
        return res;
    }

    public void inorder(TreeNode root, List<Integer> res) {
        if (root == null) {
            return;
        }
        inorder(root.left, res);//左子树
        res.add(root.val);//res 记录当前节点值
        inorder(root.right, res);//右子树
    }
}

代码实现(迭代):

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

补充说明:

方法一的递归函数我们也可以用迭代的方式实现,两种方式是等价的,区别在于递归的时候隐式地维护了一个栈,而我们在迭代的时候需要显式地将这个栈模拟出来,其他都相同,具体实现可以看下面的代码。

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值