题目描述:
给定一个二叉树的根节点 root
,返回 它的 中序 遍历 。
示例 1:
输入:root = [1,null,2,3] 输出:[1,3,2]
示例 2:
输入:root = [] 输出:[]
示例 3:
输入:root = [1] 输出:[1]
提示:
- 树中节点数目在范围
[0, 100]
内 -100 <= Node.val <= 100
解题准备:
其实这道题的代码很简单,可以说是非常基础,但是正因为流传广、基础,很多人都不了解其原理,在此大致解释一下。【本人也是新手】
1.了解二叉树:二叉树是树状结构中比较特殊的一种,从根节点看,它有且只有左子树和右子树,从每一个节点看,同样是有且仅有左右子树(左子树为null、右子树为null也看成拥有子树),具有迭代性。
2.了解基础操作:明显,对于树,仅涉及遍历(本质是查找),对于链表(因为要返回数据),只涉及添加add,难点只在于遍历。
3.了解中序遍历:X序遍历,是以根节点为标准,中序则指根节点在中间,左子树在前,右子树在后。【同理,先序是中左右,后序是左右中,左一定在右前】
4.模拟操作:
中序遍历其实一共只有三步【迭代的三步】:1st.遍历左子树。2nd.读取根节点的值。3rd.遍历右子树。
很容易发现,第1st步和第3rd步无法直接获取值,所以所有获取值的操作都落在第2nd步上,问题在于如何模拟这种操作。

解题难点1分析:
经上分析,难点1:如何遍历左子树、右子树?
【例子的基础,是图1】从二叉树的迭代性可知,root是一棵树,root.left也可以看成一棵二叉树。
比如:1是一棵树【以1为根,左子为2,右子为4】,其左子节点2也是一棵树【以2为根,左子为3,右子为null】,同理,1的右子节点4也是一棵树【以4为根,左子为5,右子为6】
注:树x是指,以x值为根的树【比如树2表示2为根的树】
对于第一步:
对图1的树中序遍历,第一步是遍历左子树,也就是树2;然而,树2是树,那么中序遍历依旧要求遍历左子树,也就是树3;树3也是树,同理……
这样下去,就无穷无尽,并且由于树3的左子树为null,还会有访问出错的问题。
解决思路:提供结束条件。
迭代左子树,明显地,当左子树为null时,就不用遍历左子树了,直接到第2步:得到本节点的值。
这里其实就是编码最困难的地方:该用root.left?还是root作为结束条件?【这个问题的本质,是如何遍历出具有迭代性的代码】
依下面的伪代码,如果root.left==null时,比如树3,无法使节点3入栈,也就是说,需要在遍历结束后,提供代码得到节点3的值(其实可以发现,依照伪代码,入栈的while完成后,一定是根节点的最左子孙节点)
只是有两个问题:1.对于最左子孙节点单独处理,不符合迭代性质。
2.将来遍历到第3步---右子树时,如何保证能单独处理最左子孙节点?
// 伪代码
// 得到左边的数据(把右子树视为null)
while(root.left!=null){
stack.push(root); // 把节点入栈
root=root.left;
}
System.out.println(root.value);
// 遍历栈中数据
while(!stack.isEmpty()){
System.out.println(stack.pop().value);
}
所以,伪代码应该改为:
不过有人会担心:如果左子树为null,岂不是访问溢出?其实null 表示没有值,但是内存为其分配了空间,如果是null.left(访问一个未分配空间的地址),才会出现异常。
这样子,当访问到树3时,会把节点3入栈,然后访问树3左子树null(不满足!=null,进入下一步),此时栈中有123(由底往上),出栈后先是3,后是2,最后是1。
// 伪代码
// 得到左边的数据(把右子树视为null)
while(root!=null){
stack.push(root); // 把节点入栈
root=root.left;
}
// 遍历栈中数据
while(!stack.isEmpty()){
System.out.println(stack.pop().value);
}
至此,访问左子节点的任务就完成了。
(root非空,是指新树来临时,栈中无数据)简化:
// 伪代码
// 得到左边的数据(把右子树视为null)
while( root!=null || !stack.isEmpty() ){
while(root!=null){
stack.push(root); // 把节点入栈
root=root.left;
}
System.out.println(stack.pop().value);
}
解题难点2分析:
虽然左子节点OK了,但是无论是根节点、还是沿途得到的子树,都没有访问过其右子树。
所以问题1:如何访问右子树?
由上可知,右子树也是一棵二叉树,比如树1的右子树树4,它也是二叉树,访问树4时,也要先访问左子树,再根节点,再右子树。
由于左子节点的访问OK,所以问题在于:如何把右子树转化为节点?【这句话的意思是:怎么把右子节点入栈】
对于图1,我们在访问树3时,其实是进行了三步的,只是其左右子树都为null,所以不处理,然而,如果树3有一右子树R,怎么办?
这时候,就要考虑,得到节点3的值后,要遍历树R。
伪代码如下:
不过运行后会发现超出内存限制了(其实while变成死循环了)
// 伪代码
// 得到左边的数据(把右子树视为null)
while( root!=null || !stack.isEmpty() ){
while(root!=null){
stack.push(root); // 把节点入栈
root=root.left;
}
// 到达root的最左子孙节点
root=stack.pop(); // 树root的最左子孙节点
System.out.println(root.value);
// null没什么好讲的,非null就得遍历右子树
if(root.right!=null){
root=root.right;
}
}
问题1:为什么会变成死循环?
易得,如果root!=null || stack非空,则进行循环,而root=pop(),如果依照图1,那么在第一次while入栈完成后,栈中有123(由底到顶),赋值后root=3,栈中12,树3无右子树,所以继续外层while循环,while入栈后,栈中有123(由底到顶)……
那么,怎么办呢?
我们知道,遍历有三步,对于树1来说,先遍历树2。
而遍历树2,就有先遍历树3【树x都同理】。
对于树2遍历,有左中右的顺序,然后到其父节点也就是节点1。
因此,如果遍历完右子树,就应该到父节点。
问题2:如何到父节点?
从while入栈循环可以得到,这一步一定会把左侧的所有节点,按照父子形式入栈(从底到顶,123分别是根--根左子--根左孙---根左……)
那么,根左子树遍历完,就应该到根,所以stack.pop()没有问题。
可是,这里由于右子树未遍历到的问题,使栈中元素死循环了。
所以,如果根树比如树3右子为null,应该要使root=null,这样子能避免重复,同时使栈中的下一个元素可以被访问。
由于当右子树为null时,root=null,并且右子树非空时,root=root.right。
所以可以复用,无需设限,直接按以下写:
// 伪代码
// 得到左边的数据(把右子树视为null)
while( root!=null || !stack.isEmpty() ){
while(root!=null){
stack.push(root); // 把节点入栈
root=root.left;
}
// 到达root的最左子孙节点
root=stack.pop(); // 树root的最左子孙节点
System.out.println(root.value);
// null没什么好讲的,非null就得遍历右子树
root=root.right;
}
代码:
/**
* 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<Integer>();
Stack<TreeNode> temp = new Stack<TreeNode>();
while( !temp.isEmpty() || root!=null ){
while(root!=null){
temp.push(root);
root=root.left;
}
root=temp.pop();
result.add(root.val);
root=root.right;
}
return result;
}
}
以上内容即我想分享的关于力扣热题5的一些知识。
我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。