题目描述
给定一个二叉树的根节点 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"两重含义
而且这种含义,必须考虑两次循环的关系,才能被分析出来
我呵呵了,这么写很简洁,但是很容易出错,而且几个人能读懂?????
所以我用了更简单的写法,不让一个变量同时包含这么多含义
我认为,算法应该被以最直白的方式翻译为程序,而不是晦涩难懂!!!!