

# 本周小结！（二叉树系列四）

> 这已经是二叉树的第四周总结了，二叉树是非常重要的数据结构，也是面试中的常客，所以有必要一步一步帮助大家彻底掌握二叉树！

## 周一

在[二叉树：合并两个二叉树](https://programmercarl.com/0617.合并二叉树.html)中讲解了如何合并两个二叉树，平时我们都习惯了操作一个二叉树，一起操作两个树可能还有点陌生。

其实套路是一样，只不过一起操作两个树的指针，我们之前讲过求 [二叉树：我对称么？](https://programmercarl.com/0101.对称二叉树.html)的时候，已经初步涉及到了 一起遍历两棵二叉树了。

**迭代法中，一般一起操作两个树都是使用队列模拟类似层序遍历，同时处理两个树的节点，这种方式最好理解，如果用模拟递归的思路的话，要复杂一些。**

## 周二

周二开始讲解一个新的树，二叉搜索树，开始要换一个思路了，如果没有利用好二叉搜索树的特性，就容易把简单题做成了难题了。

学习[二叉搜索树的特性](https://programmercarl.com/0700.二叉搜索树中的搜索.html)，还是比较容易的。

大多是二叉搜索树的题目，其实都离不开中序遍历，因为这样就是有序的。

至于迭代法，相信大家看到文章中如此简单的迭代法的时候，都会感动的痛哭流涕。

## 周三

了解了二搜索树的特性之后， 开始验证[一棵二叉树是不是二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)。

首先在此强调一下二叉搜索树的特性：

* 节点的左子树只包含小于当前节点的数。
* 节点的右子树只包含大于当前节点的数。
* 所有左子树和右子树自身必须也是二叉搜索树。

那么我们在验证二叉搜索树的时候，有两个陷阱：

* 陷阱一

**不能单纯的比较左节点小于中间节点，右节点大于中间节点就完事了**，而是左子树都小于中间节点，右子树都大于中间节点。

* 陷阱二

在一个有序序列求最值的时候，不要定义一个全局遍历，然后遍历序列更新全局变量求最值。因为最值可能就是int 或者 longlong的最小值。

推荐要通过前一个数值（pre）和后一个数值比较（cur），得出最值。

**在二叉树中通过两个前后指针作比较，会经常用到**。

本文[二叉树：我是不是一棵二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)中迭代法中为什么没有周一那篇那么简洁了呢，因为本篇是验证二叉搜索树，前提默认它是一棵普通二叉树，所以还是要回归之前老办法。

## 周四

了解了[二叉搜索树](https://programmercarl.com/0700.二叉搜索树中的搜索.html)，并且知道[如何判断二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)，本篇就很简单了。

**要知道二叉搜索树和中序遍历是好朋友！**

在[二叉树：搜索树的最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)中强调了要利用搜索树的特性，把这道题目想象成在一个有序数组上求两个数最小差值，这就是一道送分题了。

**需要明确：在有序数组求任意两数最小值差等价于相邻两数的最小值差**。

同样本题也需要用pre节点记录cur节点的前一个节点。（这种写法一定要掌握）

## 周五

此时大家应该知道遇到二叉搜索树，就想是有序数组，那么在二叉搜索树中求二叉搜索树众数就很简单了。

在[二叉树：我的众数是多少？](https://programmercarl.com/0501.二叉搜索树中的众数.html)中我给出了如果是普通二叉树，应该如何求众数的集合，然后进一步讲解了二叉搜索树应该如何求众数集合。

在求众数集合的时候有一个技巧，因为题目中众数是可以有多个的，所以一般的方法需要遍历两遍才能求出众数的集合。

**但可以遍历一遍就可以求众数集合，使用了适时清空结果集的方法**，这个方法还是很巧妙的。相信仔细读了文章的同学会惊呼其巧妙！

**所以大家不要看题目简单了，就不动手做了，我选的题目，一般不会简单到不用动手的程度，哈哈**。

## 周六

在[二叉树：公共祖先问题](https://programmercarl.com/0236.二叉树的最近公共祖先.html)中，我们开始讲解如何在二叉树中求公共祖先的问题，本来是打算和二叉搜索树一起讲的，但发现篇幅过长，所以先讲二叉树的公共祖先问题。

**如果找到一个节点，发现左子树出现结点p，右子树出现节点q，或者 左子树出现结点q，右子树出现节点p，那么该节点就是节点p和q的最近公共祖先。**

这道题目的看代码比较简单，而且好像也挺好理解的，但是如果把每一个细节理解到位，还是不容易的。

主要思考如下几点：

* 如何从底向上遍历？
* 遍历整棵树，还是遍历局部树？
* 如何把结果传到根节点的？

这些问题都需要弄清楚，上来直接看代码的话，是可能想不到这些细节的。

公共祖先问题，还是有难度的，初学者还是需要慢慢消化！

## 总结

本周我们讲了[如何合并两个二叉树](https://programmercarl.com/0617.合并二叉树.html)，了解了如何操作两个二叉树。

然后开始另一种树：二叉搜索树，了解[二叉搜索树的特性](https://programmercarl.com/0700.二叉搜索树中的搜索.html)，然后[判断一棵二叉树是不是二叉搜索树](https://programmercarl.com/0098.验证二叉搜索树.html)。

了解以上知识之后，就开始利用其特性，做一些二叉搜索树上的题目，[求最小绝对差](https://programmercarl.com/0530.二叉搜索树的最小绝对差.html)，[求众数集合](https://programmercarl.com/0501.二叉搜索树中的众数.html)。

接下来，开始求二叉树与二叉搜索树的公共祖先问题，单篇篇幅原因，先单独介绍[普通二叉树如何求最近公共祖先](https://programmercarl.com/0236.二叉树的最近公共祖先.html)。

现在已经讲过了几种二叉树了，二叉树，二叉平衡树，完全二叉树，二叉搜索树，后面还会有平衡二叉搜索树。 那么一些同学难免会有混乱了，我针对如下三个问题，帮大家在捋顺一遍：

1. 平衡二叉搜索数是不是二叉搜索树和平衡二叉树的结合？

是的，是二叉搜索树和平衡二叉树的结合。

2. 平衡二叉树与完全二叉树的区别在于底层节点的位置？

是的，完全二叉树底层必须是从左到右连续的，且次底层是满的。

3. 堆是完全二叉树和排序的结合，而不是平衡二叉搜索树？

堆是一棵完全二叉树，同时保证父子节点的顺序关系（有序）。 **但完全二叉树一定是平衡二叉树，堆的排序是父节点大于子节点，而搜索树是父节点大于左孩子，小于右孩子，所以堆不是平衡二叉搜索树**。

大家如果每天坚持跟下来，会发现又是充实的一周！[机智]

<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码.jpg width=450> </img></div>
