二叉树算法
1. 二叉树解题的思维模式分为两类
1. **通过遍历一遍二叉树得到答案**:如果可以,用一个traverse函数配合外部变量来实现,这叫 **遍历** 的思维模式
对应着 **回溯算法核心框架**
2. **是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案**:如果可以,写出这个**递归函数的定义**,并**充分利用这个函数的返回值**,这叫 **分解问题** 的思维模式
对应着 **动态规划核心框架**
核心在于:我要给递归函数一个合适的定义,然后用函数的定义来解释我的代码;如果我的逻辑成功自洽,说明算法正确
2. 二叉树遍历框架
```
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序位置
traverse(root.left);
// 中序位置
traverse(root.right);
// 后序位置
}
```
所谓前序位置,就是刚进入一个节点(元素)的时候,后序位置就是即将离开一个节点(元素)的时候
![image-20220602205929375](https://img-blog.csdnimg.cn/img_convert/a2bd4b4f378ad01447dbfd4842ea6486.png)
**前中后序位置是遍历二叉树过程中处理每一个节点的三个特殊时间点**
1. 前序位置的代码在刚刚进入一个二叉树节点的时候执行
2. 后续位置的代码在将要离开一个二叉树节点的时候执行
3. 中序位置的代码在一个二叉树节点左子树都遍历完,即将开始遍历右子树的时候执行
多叉树没有中序位置,因为二叉树的每个节点只会进行唯一一次左子树切换右子树,而多叉树节点可能有很多子节点,会多次切换
**因此二叉树的问题只需要单独思考每一个节点应该做什么,其他的不用你管,抛给二叉树遍历框架,递归会在所有节点上做相同的操作**
3. **遇到一道二叉树的题目时的通用思考过程**
1. 是否可以通过遍历一遍二叉树得到答案?如果可以,用一个traverse函数配合外部变量来实现
2. 是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值
3. 无论使用哪一种思维方式,你都要明白二叉树的每一个节点需要做什么,需要在什么时候(前中后序)做
4. 后序位置的特殊之处
1. 中序位置主要用于BST数组,可以把BST的中序遍历认为是遍历有序数组
2. 前序位置没有什么特殊的,只不过我们习惯把那些对前中后序位置不敏感的代码写在前序位置罢了
3. 关于 **前序位置是刚刚进入节点的时刻,后序位置是即将离开节点的时刻** 的解读
意味着**前序位置的代码只能从函数参数中获取父节点传递来的参数**,而**后续位置的代码不仅可以获取参数数据,还可以获取到子树通过函数返回值传递回来的数据**
**换句话说,一旦发现题目和子树有关,大概率要给函数设置合理的定义和返回值,在后序位置写代码了**
5. 层序遍历框架
void levelTraverse(TreeNode root) {
if (root == null) return;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
//从上到下遍历二叉树的每一层
while (!q.isEmpty()) {
int size = q.size();
//从左到右遍历每一层的每个节点
for (int i = 0; i < size; i++) {
TreeNode cur = q.poll();
//将下一层节点放入队列
if (cur.left != null) {
q.offer(cur.left);
}
if (cur.right != null) {
q.offer(cur.right);
}
}
}
}
```