LeetCode94. 二叉树的中序遍历 以及关于二叉树的思考

博客围绕二叉树中序遍历展开,介绍中序遍历定义,阐述使用Stack实现中序遍历的步骤。还指出层序遍历是树的BFS遍历,前序、中序、后序遍历是树的DFS遍历,最后强调实现算法的代码应具高可读性,给出更简单的写法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

示例 1:

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

思想:

中序遍历定义: 先访问最左的结点,然后访问自己,然后访问右结点

 二叉树有3个元素,左子树,根,右子树

看三个元素太不方便,我试着只看一个元素,也就是

 

使用Stack实现中序,我需要一个Stack<treeNode> s以及一个treeNode root

 

中序:先访问左子树,再访问根,再访问右子树

由于题目条件的二叉树,都是只给出root结点

STEP1:

已知root,但不访问root,先访问root.left,即root=root.left

但是未来访问完了root.left后,还是需要访问root的,所以使用一个stack<treeNode>记录之前 "经过" 的root

STEP2:

当发现root.left为空时,说明root的左子树访问完了,此时该访问root了

STEP3:

访问root后,就需要访问root.right,即root=root.right

 

思考完毕,其中关于二叉树有一点泛用性的

对于二叉树,与其关注3个元素,不如只关注root的相对关系”

层序遍历本质上是"树的BFS遍历"

可以发现,层序遍历是按层访问,一层访问完再访问一层

这就相当于bfs每轮访问都会访问"已访问节点的所有子节点"

BFS使用for循环实现的 "逻辑结构",是队列

前序,后续,中序遍历本质上是"树的DFS遍历"

前序后续遍历的过程都是顺着一个结点,一直走到结点没有子节点后再返回,就和DFS一样

DFS使用for循环实现的 "逻辑结构" , 是栈

(注意!!! 我们在把 "递归转换为循环" 的时候,总是喜欢使用栈,但是这里 "DFS的栈""递归转换为循环栈" 原理不一样的)

(DFS的栈 更加类似于 在 "循环这种编程逻辑" 下,模拟树的路径,在树枝上行走 的过程, 而不是 模拟递归这种编程逻辑)

AC代码,注释才是本体(滑稽)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> result = new ArrayList<>();
        Stack<TreeNode> s = new Stack<TreeNode>();
        boolean hasTrav = false;
        while(root!=null||!s.empty()){
            //已知root,但不访问root,先访问root.left,即root=root.left
            while(root.left!=null && hasTrav==false){
                s.push(root);
                root=root.left;
            }
            hasTrav=false;
            //当发现root.left为空时,说明root的左子树访问完了,此时该访问root了(这个条件在while循环那里)
            //System.out.println(root.val);
            result.add(root.val);
            //访问root后,就需要访问root.right,即root=root.right
            //如果root.right不为空,则
            if(root.right!=null) {
                root = root.right;
            }
            //如果root.right也为空,则表明,[以root为根的树已经被访问完毕]此时需要回溯到上一级
            else if(!s.empty()){
                root = s.pop();
                hasTrav = true;//说明 [上一层根结点] 的 [left子树(结点)] 已经被访问过
            }
            else{//如果栈也是空的,则root弄成null,表示整个树都被访问完了
                root = null;
            }
        }
        return result;
    }
}

实现算法的代码应该可读性高!!

网上的代码全都是人云亦云,清一色用了很高级的写法
一个变量root代表了很多很多的含义,比如while循环的那个root==null就同时代表了"左子树已经被访问完毕"以及其本身的"root==null"两重含义
而且这种含义,必须考虑两次循环的关系,才能被分析出来
我呵呵了,这么写很简洁,但是很容易出错,而且几个人能读懂?????
所以我用了更简单的写法,不让一个变量同时包含这么多含义

我认为,算法应该被以最直白的方式翻译为程序,而不是晦涩难懂!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值