二叉树 | 7. 总结

参考:
代码随想录:二叉树总结篇

0、二叉树的理论基础

二叉树的种类、存储方式、遍历方式、定义方式

0.1 二叉树的种类

  • 满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上
    深度为k,有2^k-1个节点的二叉树
  • 完全二叉树:除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。
    若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
  • 二叉搜索树
    有序树;
    若左子树不空,左子树上所有结点的值均小于它的根结点的值;
    若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
    左、右子树也分别为二叉排序树;
  • 平衡二叉搜索树(AVL(Adelson-Velsky and Landis)树)
    空树或它的左右两个子树的高度差的绝对值不超过1,
    并且左右两个子树都是一棵平衡二叉树。

0.2 递归三部曲

  • 确定递归函数的参数和返回值
  • 确定终止条件
    // 空节点,返回0
    if (node == NULL) return 0; 
    // 插入节点
    if (root == NULL) {
          
          
    	TreeNode* node = new TreeNode(val);
    	return node;
    }
    //或者
    // 找到叶子节点,就开始结束的处理逻辑
    if (cur->left == NULL && cur->right == NULL) {
          
          
    	终止处理逻辑
    }
    
  • 确定单层递归的逻辑:调用递归的地方

0.3 递归函数什么时候要有返回值

  • 搜索 整棵二叉树不用处理递归返回值,递归函数就不要返回值。
    113.路径总和ii
  • 搜索 整棵二叉树需要处理递归返回值,递归函数就需要返回值。
    236. 二叉树的最近公共祖先
  • 搜索 其中一条符合条件的路径,那么递归 一定需要返回值
    112. 路径总和
    98.验证二叉搜索树

0.4 遍历顺序

  • 涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。
  • 普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。
    一般为后序,例如单纯求深度就用前序,
    二叉树:找所有路径 也用了前序,这是为了方便让父节点指向子节点。
  • 二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。

0.5 深度 & 高度

联系:根节点的高度就是二叉树的最大深度

  • 深度:从 根节点 到 该节点 的 最长简单路径边 的条数。
    根节点是1,依次递增。 用 前序遍历(中左右)
  • 高度:从 该节点 到 叶子节点 的 最长简单路径边 的条数。
    根节点最高,依次递减。 用 后序遍历(左右中)

0.6 在递归中如何记录前一个节点的指针

class Solution {
    
    
private:
	int result = INT_MAX;
	TreeNode* pre = NULL;
	void traversal(TreeNode* cur) {
    
    
    	if (cur == NULL) return;
    	traversal(cur->left);   // 左
    	if (pre != NULL){
    
           // 中
        	result = min(result, cur->val - pre->val);
    	}
    pre = cur; // 记录前一个
    traversal(cur->right);  // 右
	}
public:
    int getMinimumDifference(TreeNode* root) {
    
    
        traversal(root);
        return result;
    }
};

1、二叉树的遍历方式

1.1 深度优先遍历

  • 二叉树:前中后序递归法 :递归三部曲初次亮相
  • 二叉树:前中后序迭代法(一):通过栈模拟递归
  • 二叉树:前中后序迭代法(二)统一风格

1.2 广度优先遍历

  • 二叉树的层序遍历:通过队列模拟

2、求二叉树的属性

2.1 二叉树:是否对称

  • 递归:后序(左右中),比较的是根节点的左子树与右子树是不是相互翻转
  • 迭代:使用队列/栈将两个节点顺序放入容器中进行比较

2.2 二叉树:求最大深度

  • 递归:后序(左右中),求根节点最大高度就是最大深度,通过递归函数的返回值做计算树的高度
  • 迭代:层序遍历

2.3 二叉树:求最小深度

  • 递归:后序(左右中),求根节点最小高度就是最小深度,注意最小深度的定义
  • 迭代:层序遍历

2.4 二叉树:求有多少个节点

  • 递归:后序(左右中),通过递归函数的返回值计算节点数量
  • 迭代:层序遍历

2.5 二叉树:是否平衡

  • 递归:后序(左右中),注意后序求高度和前序求深度,递归过程判断高度差
  • 迭代:效率很低,不推荐

2.6 二叉树:找所有路径

  • 递归:前序(中左右),方便让父节点指向子节点,涉及回溯处理根节点到叶子的所有路径
  • 迭代:一个栈模拟递归,一个栈来存放对应的遍历路径

2.7 二叉树:递归中如何隐藏着回溯

2.8 二叉树:求左叶子之和

  • 递归:后序(左右中),必须三层约束条件,才能判断是否是左叶子。
  • 迭代:直接模拟后序遍历

2.9 二叉树:求左下角的值

  • 递归:顺序无所谓,优先左孩子搜索,同时找深度最大的叶子节点。
  • 迭代:层序遍历找最后一行最左边

2.10 二叉树:求路径总和

  • 递归:顺序无所谓,递归函数返回值为bool类型是为了搜索一条边,没有返回值是搜索整棵树。
  • 迭代:栈里元素不仅要记录节点指针,还要记录从头结点到该节点的路径数值总和

3、二叉树的修改与构造

3.1 翻转二叉树

  • 递归:前序(中左右),交换左右孩子
  • 迭代:直接模拟前序遍历

3.2 构造二叉树

  • 递归:前序(中左右),重点在于找分割点,分左右区间构造
  • 迭代:比较复杂,意义不大

3.3 构造最大的二叉树

  • 递归:前序(中左右),分割点为数组最大值,分左右区间构造
  • 迭代:比较复杂,意义不大

3.4 合并两个二叉树

  • 递归:前序(中左右),同时操作两个树的节点,注意合并的规则
  • 迭代:使用队列,类似层序遍历

4、求二叉搜索树的属性

4.1 二叉搜索树中的搜索

  • 递归:二叉搜索树的递归是有方向的
  • 迭代:因为有方向,所以迭代法很简单

4.2 是不是二叉搜索树

  • 递归:中序(左中右),相当于变成了判断一个序列是不是递增的
  • 迭代:模拟中序,逻辑相同

4.3 求二叉搜索树的最小绝对差

  • 递归:中序(左中右),双指针操作
  • 迭代:模拟中序,逻辑相同

4.4 求二叉搜索树的众数

  • 递归:中序(左中右),清空结果集的技巧,遍历一遍便可求众数集合
  • 二叉搜索树转成累加树
  • 递归:中序(左中右),双指针操作累加
  • 迭代:模拟中序,逻辑相同

5、二叉树公共祖先问题

5.1 二叉树的公共祖先问题

  • 递归:后序(左右中),回溯,找到左子树出现目标值,右子树节点目标值的节点。
  • 迭代:不适合模拟回溯

5.2 二叉搜索树的公共祖先问题

  • 递归:顺序无所谓,如果节点的数值在目标区间就是最近公共祖先
  • 迭代:按序遍历

6、二叉搜索树的修改与构造

6.1 二叉搜索树中的插入操作

  • 递归:顺序无所谓,通过递归函数返回值添加节点
  • 迭代:按序遍历,需要记录插入父节点,这样才能做插入操作

6.2 二叉搜索树中的删除操作

  • 递归:前序(中左右),想清楚删除非叶子节点的情况
  • 迭代:有序遍历,较复杂

6.3 修剪二叉搜索树

  • 递归:前序(中左右),通过递归函数返回值删除节点
  • 迭代:有序遍历,较复杂

6.4 构造二叉搜索树

  • 递归:前序(中左右),数组中间节点分割
  • 迭代:较复杂,通过三个队列来模拟

猜你喜欢

转载自blog.csdn.net/weifengomg/article/details/129091011