0
点赞
收藏
分享

微信扫一扫

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)


文章目录

  • ​​树的遍历​​
  • ​​深度优先遍历​​
  • ​​1、二叉树前序遍历(LeetCode 144)​​
  • ​​1)示例​​
  • ​​2)思路​​
  • ​​3)代码(递归版本)​​
  • ​​4)代码(迭代版本)​​
  • ​​2、二叉树中序遍历(LeetCode 94)​​
  • ​​1)示例​​
  • ​​2)思路​​
  • ​​3)代码(递归版本)​​
  • ​​4)代码(迭代版本)​​
  • ​​3、二叉树的后序遍历(LeetCode 45)​​
  • ​​1)示例​​
  • ​​2)思路​​
  • ​​3)代码(递归版本)​​
  • ​​4)代码(迭代版本)​​
  • ​​深度优先遍历总结​​
  • ​​广度优先遍历​​
  • ​​4、二叉树的层序遍历(LeetCode 102)​​
  • ​​1)示例​​
  • ​​2)思路​​
  • ​​3)代码​​
  • ​​5、二叉树的层序遍历 II(LeetCode 107)​​
  • ​​1)示例​​
  • ​​2)思路​​
  • ​​3)代码​​

树的遍历

本文聊一下树的两大种(深度优先遍历、广度优先遍历)、四小种(前序遍历、中序遍历、后序遍历、层序遍历)

深度优先遍历

二叉树的深度优先遍历方式有三种:前序遍历、中序遍历、后序遍历。本文主要基于递归算法讨论。

  • 前序遍历:遍历顺序为​​跟节点 --> 左子节点 --> 右子节点​
  • 中序遍历:遍历顺序为​​左子节点 --> 跟节点 --> 右子节点​
  • 后序遍历:遍历顺序为​​左子节点 --> 右子节点 --> 根节点​

1、二叉树前序遍历(LeetCode 144)

给你二叉树的根节点 ​​root​​ ,返回它节点值的 前序 遍历。

1)示例

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_java


【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_迭代_02

2)思路

按照访问根节点 --> 左子树 --> 右子树的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。整个遍历过程天然具有递归的性质。

3)代码(递归版本)

/**
* 前序遍历 (LeetCode 144)
* 方法:递归
*/
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
pre(root, res);
return res;
}

public static void pre(TreeNode head, List<Integer> list) {
if (head == null) {
return;
}
list.add(head.val);
pre(head.left, list);
pre(head.right, list);
}

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_java_03

4)代码(迭代版本)

用迭代的方式实现递归函数,两种方式本质上是等价的。区别在于递归的时候隐式地维护了一个栈,而迭代则需要显式地将这个栈模拟出来。

/**
* 前序遍历 (LeetCode 144)
* 方法:迭代
*/
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<>();
TreeNode node = root;
while (!stack.isEmpty() || node != null) {
while (node != null) {
res.add(node.val);
stack.push(node);
node = node.left;
}
node = stack.pop();
node = node.right;
}
return res;
}

2、二叉树中序遍历(LeetCode 94)

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

1)示例

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_迭代_04

2)思路

按照访问左子树 --> 根节点 --> 右子树的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。整个遍历过程天然具有递归的性质。

3)代码(递归版本)

/**
* 中序遍历(LeetCode 94)
* 方法:递归
*/
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
in(root, res);
return res;
}

public void in(TreeNode head, List<Integer> list) {
if (head == null) {
return;
}
in(head.left, list);
list.add(head.val);
in(head.right, list);
}

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_迭代_05

4)代码(迭代版本)

用迭代的方式实现递归函数,两种方式本质上是等价的。区别在于递归的时候隐式地维护了一个栈,而迭代则需要显式地将这个栈模拟出来。

/**
* 中序遍历 (LeetCode 94)
* 方法:迭代
*/
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<>();
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}

3、二叉树的后序遍历(LeetCode 45)

给你一棵二叉树的根节点 ​​root​​ ,返回其节点值的 后序 遍历 。

1)示例

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_二叉树_06

2)思路

按照访问左子树 --> 右子树 --> 根节点的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。整个遍历过程天然具有递归的性质。

3)代码(递归版本)

/**
* 后序遍历(LeetCode)
* 方法:递归
*/
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
post(root, res);
return res;
}

public void post(TreeNode head, List<Integer> list) {
if (head == null) {
return;
}
post(head.left, list);
post(head.right, list);
list.add(head.val);
}

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_二叉树_07

4)代码(迭代版本)

用迭代的方式实现递归函数,两种方式本质上是等价的。区别在于递归的时候隐式地维护了一个栈,而迭代则需要显式地将这个栈模拟出来。

/**
* 后序遍历 (LeetCode 145)
* 方法:迭代
*/
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<>();
TreeNode prev = null;
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (root.right == null || root.right == prev) {
res.add(root.val);
prev = root;
root = null;
} else {
stack.push(root);
root = root.right;
}
}
return res;
}

深度优先遍历总结

前序遍历、中序遍历、后序遍历的区别在于业务处理的时机,也就是遍历根节点的时机,所以我们可以抽象出一个通用的深度优先遍历函数;

enum OrderType {
PRE,
IN,
POST
}

public void deepOrder(TreeNode head, List<Integer> res, OrderType type) {
if (head == null) {
return;
}
// 1,业务操作放这里,就是前序
if (Objects.equals(type, OrderType.PRE)) {
res.add(head.val);
}
deepOrder(head.left, res, type);
// 2,业务操作放这里,就是中序
if (Objects.equals(type, OrderType.IN)) {
res.add(head.val);
}
deepOrder(head.right, res, type);
// 3,业务操作放这里,就是后序
if (Objects.equals(type, OrderType.POST)) {
res.add(head.val);
}
}

广度优先遍历

广度优先遍历是按层层推进的方式,遍历每一层的节点。

4、二叉树的层序遍历(LeetCode 102)

给你二叉树的根节点 ​​root​​ ,返回其节点值的 层序 遍历 。 (即逐层地,从左到右访问所有节点)。

1)示例

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_算法_08

2)思路

首先将根节点放入一个队列,然后迭代队列不为空的情况,每次取出队列中当前时间点 的 size个数量的节点,然后遍历这些节点,将这些节点的左子节点、右子节点依次放入到队列中。

3)代码

public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
// 只取一层的数据
int size = queue.size();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode treeNode = queue.poll();
list.add(treeNode.val);
if (treeNode.left != null)
queue.add(treeNode.left);
if (treeNode.right != null) {
queue.add(treeNode.right);
}
}
res.add(list);
}
return res;
}

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_算法_09

5、二叉树的层序遍历 II(LeetCode 107)

给你二叉树的根节点 ​​root​​ ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

1)示例

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_java_10

2)思路

这个题和上一题(二叉树的层序遍历(LeetCode 102))基本一模一样,区别在于这题的结果集添加方式为每遍历完一层,就把这一层的数据放在结果期的最前面。

3)代码

public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
// 只取一层的数据
int size = queue.size();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode treeNode = queue.poll();
list.add(treeNode.val);
if (treeNode.left != null)
queue.add(treeNode.left);
if (treeNode.right != null) {
queue.add(treeNode.right);
}
}
res.add(0, list);
}
return res;
}

【算法100天 | 7】二叉树的前序、中序、后序、层序遍历(递归和迭代两种实现)_算法_11


举报

相关推荐

0 条评论