一、需求
给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [1]
输出:[1]
示例 4:
输入:root = [1,2]
输出:[1,2]
示例 5:
输入:root = [1,null,2]
输出:[1,2]
提示:
- 树中节点数目在范围
[0, 100]
内 -100 <= Node.val <= 100
**进阶:**递归算法很简单,你可以通过迭代算法完成吗?
二、思路分析图
三、代码
(一)公共代码(树节点类)
package com.bessky.pss.wzw.SuanFa;
import java.util.ArrayList;
import java.util.List;
/**
* 树节点类
*
* @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;
}
/**
* 遍历显示
*
* @return
*/
public String display()
{
// 创建存储先序遍历后的结果
List<Integer> results = new ArrayList<>();
// 调用:递归方法
this.inorder(this, results);
return results.toString();
}
/**
* 递归方法体
*
* @param root
* @param results
*/
public void inorder(TreeNode root, List<Integer> results)
{
if (root == null)
{
return;
}
// 调用:当最左时就存储 || 或左没有时存储
results.add(root.val);
// 调用:递归方法(先把最左边的拿到)
inorder(root.left, results);
// 调用:递归方法(左没有时就递归右边)
inorder(root.right, results);
}
}
(二)数据初始化
/**
* 入口
* 144、二叉树的前序遍历
* 输入:
* [1,null,2,3]
* 输出:
* [1,2,3]
* 解释:
* 1.递归方案
* 2.迭代方案
*/
@Test
public void suanfa33()
{
// 初始化
TreeNode root = new TreeNode(1, null, new TreeNode(2, new TreeNode(3), null));
// 打印
List<Integer> result1 = new ArrayList<>();
this.recursionPreorderTraversal(root, result1);
System.out.println("递归方案 = " + result1.toString());
List<Integer> result2 = new ArrayList<>();
this.iterationPreorderTraversal(root, result2);
System.out.println("迭代方案 = " + result2.toString());
List<Integer> result3 = new ArrayList<>();
this.morrisPreorderTraversal(root, result3);
System.out.println("morris方案 = " + result3.toString());
}
(三)递归方案
/**
* 递归方案
*
* @param root
* @param result
*/
private void recursionPreorderTraversal(TreeNode root, List<Integer> result)
{
if (root == null)
{
return;
}
result.add(root.val);
this.recursionPreorderTraversal(root.left, result);
this.recursionPreorderTraversal(root.right, result);
}
(四)迭代方案
/**
* 迭代方案
*
* @param root
* @param result
*/
private void iterationPreorderTraversal(TreeNode root, List<Integer> result)
{
// 如果root为 null
if (root == null)
{
// 直接返回
return;
}
// 将root的值加入到集合中
result.add(root.val);
// root赋值到临时对象中
TreeNode temp = root;
// 声明堆对象
Stack<TreeNode> stack = new Stack<>();
// 将root加入到堆对象
stack.push(root);
// 循环(条件:堆 不为 空)
while (!stack.isEmpty())
{
// 获取顶点节点
TreeNode peek = stack.peek();
// 获取顶节点左子节点
TreeNode left = peek.left;
// 获取顶节点右子节点
TreeNode right = peek.right;
// 左节点 不等于 null && 左节点 不等于 临时节点 && 右节点 不等于 临时节点
if (left != null && left != temp && right != temp)
{
// 添加左节点的值
result.add(left.val);
// 加入左节点到堆中
stack.push(left);
}
// 否则 如果 (右节点 不为 null && 右节点 不等于临时节点)
else if (right != null && right != temp)
{
// 添加右节点的值
result.add(right.val);
// 加入右节点到堆中
stack.push(right);
}
// 否则
else
{
// 将顶节点赋值到临时节点
temp = peek;
// 清除栈的顶节点
stack.pop();
}
}
}
(五)Morris方案
/**
* Morris方案
*
* @param root
* @param result
*/
private void morrisPreorderTraversal(TreeNode root, List<Integer> result)
{
// root如果为空
if (root == null)
{
// 直接返回
return;
}
// 声明p1存放root,声明p2
TreeNode p1 = root, p2;
// 循环(条件:p1 不等于 null)
while (p1 != null)
{
// 将左节点给p2
p2 = p1.left;
// 如果p2 不等于 null
if (p2 != null)
{
// 循环(条件:p2右节点 不等于 null && p2右节点 不等于 p1)
while (p2.right != null && p2.right != p1)
{
// 将p2右节点赋值到p2节点
p2 = p2.right;
}
// p2右节点 等于null
if (p2.right == null)
{
// 添加p1的值
result.add(p1.val);
// 将p1 赋值到p2右节点(这里应该是最右节点)
p2.right = p1;
// p1左节点赋值到p1
p1 = p1.left;
continue;
}
}
else
{
// 添加p1的值
result.add(p1.val);
}
// p1右节点赋值p1
p1 = p1.right;
}
}
(六)结果图
作者:王子威
四、总结
- 学习了二叉树的前序遍历
- 递归方案技巧:前序遍历(添加放前面),中序遍历(添加放中间),后序遍历(添加放后面)
- Morris还是不能直接默写,感觉理解的还是不透彻
- 迭代一开始蒙的,完全忘记了使用Stack堆的特性
- Stack堆,先进先出,和队列是同样的,所以这里队列也可以做
- 算法兴趣+1 总:33
- 加强了对算法的分析能力