一、直观表现
以上述中,前中后序遍历顺序如下:
前序遍历(中左右):5 4 1 2 6 7 8
中序遍历(左中右):1 4 2 5 7 6 8
后序遍历(左右中):1 2 4 7 8 6 5
二、递归算法
在说二叉树的递归算法前,我们先了解下什么是递归算法
2.1 核心思想
递归算法!既要有递去的过程,也需要有归来的过程。主要总结如下三步
1.确定终止条件:
2.确定终止条件时的递归函数的参数和返回值:
3.提取重复逻辑,化大为小
2.2 递归的编程模型
模型一: 在递去的过程中解决问题
function recursion(大规模){
if (end_condition){ // 明确的递归终止条件
end; // 简单情景
}else{ // 在将问题转换为子问题的每一步,解决该步中剩余部分的问题
solve; // 递去
recursion(小规模); // 递到最深处后,不断地归来
}
}
模型二: 在归来的过程中解决问题
function recursion(大规模){
if (end_condition){ // 明确的递归终止条件
end; // 简单情景
}else{ // 先将问题全部描述展开,再由尽头“返回”依次解决每步中剩余部分的问题
recursion(小规模); // 递去
solve; // 归来
}
}
2.3 二叉树的遍历
2.3.1 前序遍历
public static void preOrderRecur(TreeNode head) {
if (head == null) {//2.确定
return;//1.确定函数的返回值
}
//3.递归的真正处理逻辑
//3.1 先中
System.out.print(head.value + " ");
//3.2 再左
preOrderRecur(head.left);
//3.2 再右
preOrderRecur(head.right);
}
2.3.2 中序遍历
public static void preOrderRecur(TreeNode head) {
if (head == null) {
return;
}
preOrderRecur(head.left);
System.out.print(head.value + " ");
preOrderRecur(head.right);
}
2.3.3 后序遍历
public static void postOrderRecur(TreeNode head) {
if (head == null) {
return;
}
postOrderRecur(head.left);
postOrderRecur(head.right);
System.out.print(head.value + " ");
}
三、迭代算法
问题的递归实现转换成非递归实现一般需要两步工作:
(1). 自己建立“堆栈(一些局部变量)”来保存这些内容以便代替系统栈,比如树的三种非递归遍历方式;
(2). 把对递归的调用转变为对循环处理。
3.1 前序遍历的迭代算法
思想:按照先处理中间节点、再使用栈的数据结构,按右节点、左节点入栈
步骤 | 操作 | 栈 |
1 | 打印节点5 | 节点6、节点4 |
2 | 打印节点4 | 节点6、节点2、节点1 |
3 | 打印节点1 | 节点6、节点2 |
4 | 打印节点2 | 节点6 |
5 | 打印节点6 | 节点8、节点7 |
6 | 打印节点7 | 节点8 |
7 | 打印节点8 | null |
public static void preOrderIteration(TreeNode head) {
if (head == null) {
return;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(head);
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
System.out.print(node.value + " ");
if (node.right != null) {
stack.push(node.right);
}
if (node.left != null) {
stack.push(node.left);
}
}
}
四、层序遍历
题目:
从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。
例如:
给定二叉树: [3,9,20,null,null,15,7],3
/ \
9 20
/ \
15 7
返回:[3,9,20,15,7]
解题思路,层序遍历时需要一个容器,队列(先进先出)
步骤 | 操作 | 栈 |
1 | 打印节点3 | 节点9、节点20 |
2 | 打印节点9 | 节点20 |
3 | 打印节点20 | 节点15、节点7 |
4 | 打印节点15 | 节点7 |
5 | 打印节点7 | null |
代码思路
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] levelOrder(TreeNode root) {
if(root == null) return new int[0];
int[] res;
List<Integer> list = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
list.add(node.val);//打印节点
if(node.left != null)
queue.add(node.left);//左子树入队
if(node.right != null)
queue.add(node.right);右子树入队
}
Integer[] arr = list.toArray(new Integer[list.size()]);
res = new int[arr.length];
for(int i = 0; i < arr.length; i ++)
res[i] = arr[i];
return res;
}
}
题目2:
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:输入:root = [1]
输出:[[1]]
示例 3:输入:root = []
输出:[]
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();//定义外层
if (root == null) {
return ret;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.offer(root);
while (!queue.isEmpty()) {
List<Integer> level = new ArrayList<Integer>();//定义内层
int currentLevelSize = queue.size();
for (int i = 1; i <= currentLevelSize; ++i) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
ret.add(level);
}
return ret;
}
}