一、需求
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
提示:
- 树中节点数目在范围 [0, 100] 内
- -100 <= Node.val <= 100
进阶:
递归算法很简单,你可以通过迭代算法完成吗?
二、思路图
迭代思路图
初始化
第一步
第二步
第三步
第四步
第五步
第六步
三、代码
提供的TreeNode类
package com.bessky.pss.wzw.SuanFa;
/**
* 94. 二叉树的中序遍历
*
* @author 王子威
* @date 2022/7/27
*/
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;
}
}
测试方法
/**
* 入口
* 94. 二叉树的中序遍历
* 1.创建链表
* 输入:
* TreeNode root = [1,null,2,3]
* 输出:
* results.toString() = [1,3,2]
* 解释:
* 1.递归
* 2.迭代
* 3.morris中序遍历
*/
@Test
public void suanfa19()
{
// 创建链表
TreeNode root = new TreeNode(1);
root.right = new TreeNode(2);
root.right.left = new TreeNode(3);
// 调用方法:递归
List<Integer> results1 = this.recursionInorderTraversal(root);
System.out.println("results1.toString() = " + results1.toString());
// 调用方法:迭代
List<Integer> results2 = this.iterationInorderTraversal(root);
System.out.println("results2.toString() = " + results2.toString());
// 调用方法:morris 中序遍历
List<Integer> results3 = this.morrisInorderTraversal(root);
System.out.println("results3.toString() = " + results3.toString());
}
递归方案
/**
* 递归(一般面试都不让写这个,都是写 迭代 或 Morris中序遍历)
*
* @param root
* @return
*/
public List<Integer> recursionInorderTraversal(TreeNode root) {
// 创建存储中序遍历后的结果
List<Integer> results = new ArrayList<>();
// 调用:递归方法
this.inorder(root, results);
return results;
}
递归方法体
/**
* 递归方法体
* @param root
* @param results
*/
public void inorder(TreeNode root, List<Integer> results){
if (root == null)
{
return;
}
// 调用:递归方法(先把最左边的拿到)
inorder(root.left, results);
// 调用:当最左时就存储 || 或左没有时存储
results.add(root.val);
// 调用:递归方法(左没有时就递归右边)
inorder(root.right, results);
}
迭代方案
/**
* 迭代
* 栈:压进1 弹出1 压进2 压进3 弹出3 弹出2
* results = [1,3,2]
*
* @param root
* @return
*/
public List<Integer> iterationInorderTraversal(TreeNode root) {
// 创建存储中序遍历后的结果
List<Integer> results = new ArrayList<>();
// Deque可以用于做栈,等价与Stack类
Deque<TreeNode> stk = new LinkedList<>();
// 循环(root不等于空 或 栈不等于空)
// stk 一开始会为空
// 当没有左节点时会为空
while (root != null || !stk.isEmpty())
{
// root不等于空(已经是最左节点)
while (root != null)
{
// 记录到栈中
stk.push(root);
// 然后到下一个左节点
root = root.left;
}
// 弹出栈中最下面1个(因为这里经过循环等于null,所以要弹出赋值)
root = stk.pop();
// 获取节点中的值
results.add(root.val);
// 尽然到最左边,当前节点有右边的右节点吗
root = root.right;
}
return results;
}
morris 中序遍历
public List<Integer> morrisInorderTraversal(TreeNode root)
{
List<Integer> results = new ArrayList<>();
TreeNode temp = null;
while (root != null)
{
// 如果当前节点的左节点不为空
if (root.left != null)
{
// 将左节点放到临时节点上
temp = root.left;
// 如果临时节点的右节点不为空 并且 右节点不等于当前当前节点
while (temp.right != null && temp.right != root)
{
// 就把右节点放入到临时节点(直到节点到最右)
temp = temp.right;
}
// 如果节点到最右
if (temp.right == null)
{
// 把当前节点放右边(当清空所有右节点,要回到当前的节点的)
temp.right = root;
root = root.left;
}
else
{
// 把当前节点记录(左右都没有更底层的节点了)
results.add(root.val);
// 恢复节点为null 状态
temp.right = null;
// 开始当前节点的右节点
root = root.right;
}
}
else
{
// 如果当前节点的左节点没有,直接添加当前节点值
results.add(root.val);
// 左边没有,就将右节点放入到当前节点(右节点也可能有左右节点)
root = root.right;
}
}
return results;
}
结果图
作者:王子威
四、总结
- 学习了二叉树的中序遍历算法
- 再次认识到了自己菜鸡能力,3个算法看了一星期才理解通了一点
- morris是在最右加入一个root,用于返回
- 迭代是利用栈的特性进行root的记录返回
- 在日常中如果遇到,还是用递归会感觉方便些
- 算法兴趣+1 总:19
- 加强了对算法的分析能力