1. 树的定义和基本概念
树:n(>= 0)个结点构成的有限集合。
节点的度:节点的子树数目,即有多少子树,该节点的度就是多少。
树的度:所有节点中最大的度数。
叶节点:度为0的节点。
路径和路径长度:节点a到节点b的路径就是二者之间的节点序列,边数为路径长度。
祖先节点:root到某个节点的路径上的所有节点都是该节点的祖先节点。
子孙节点:某个节点的所有子树中的节点都是该节点的子孙节点。
层次:根节点在第一层,往下依次递增。
树的深度(高度):树的层数。
2. 树的特点
子树是不相交的。
除了根节点,每个节点有且仅有一个父节点。
n个结点的树,有n-1条边。
任意两个结点之间有且只有一条路径。
3. 二叉树
树的一种,除叶节点外,每个节点最多只有两个子树。
注意,二叉树中的某个节点,即使只有一个子树,也要区分左右。
3.1 二叉树分类
3.1.1 斜二叉树
每个节点都只有一个左子树 或者 都只有一个右子树,此时,二叉树退化成链表了。
3.1.2 完美二叉树(满二叉树)
除了叶节点,每个节点都有两个子节点,并且所有的叶节点都在同一层。
3.1.3 完全二叉树
可以理解为完美(满)二叉树的一种特殊情况,只允许最后一层的右边节点缺失,其他部分必须是满的。
注意,同样节点个数的各种二叉树中,完全二叉树的深度最小。
3.2 二叉树性质
- 第 i 层最多有2i-1个节点
- 深度为k的二叉树,最多有2k-1个节点(等比数列前n项和)。
- 设度为0节点个数为n0,度为1的节点个数为n1,度为2的节点个数为n2,则有n0=n2+1。
性质3证明:
二叉树节点总数是n0+n1+n2,所以他的边数是n0+n1+n2-1。
度为0的节点向下贡献的边数是 0xn0,度为1的节点向下贡献的边数是 1xn1,度为2的节点向下贡献的边数是 2xn2。
所以有等式 n 0 + n 1 + n 2 − 1 = 0 x n 0 + 1 x n 1 + 2 x n 2 n0+n1+n2-1 = 0xn0 + 1xn1 + 2xn2 n0+n1+n2−1=0xn0+1xn1+2xn2成立,即可得出性质3的关系式。
- 有n个节点的完全二叉树深度为 log(n) + 1向下取整 ,这个可以根据性质2反推出来。
- 对于一颗完全二叉树来说,根节点序号为1,则其他节点有如下规律:
若一个节点的序号是 i, 那么他的左子节点序号是 2 * i,右子节点的序号是 2 * i + 1
3.3 二叉树的遍历
先序----根 左 右----递归
中序----左 根 右----递归
后序----左 右 根----递归
层序----从上到下,从左到右----宽度优先搜索
3.3.1 遍历的典型应用
求树的深度
输出所有的叶子节点
由两种遍历的结果确定一颗二叉树(必须要有中序遍历)
3.3 二叉树的顺序存储
用数组,编号从1开始存储(从0开始也可,那么根节点序号和左右节点序号的关系式要稍微改一下)。
这种存储方式对于完全二叉树或者完美二叉树来说比较好,存储空间利用率比较高,如果是一般的二叉树(比较稀疏)用这种方式进行存储就会造成空间浪费。
3.4 二叉树的链式存储
struct Node{
int val;
Node* left;
Node* right;
}
4. 二叉搜索树
搜索:静态查找、动态查找
4.1 概念
左子树的值都比根节点小,右子树的值都比右节点大,且左右子树都是二叉搜索树。
4.2 查找(logN)
相当于二分查找,X与根节点的值比较,如果X小于根节点的值,就往左子树去找,若大于,就往右子树去找。
4.2.1 找min和max值
整棵树的最小值一定在最左分支的叶子节点上。
整棵树的最大值一定在最右分支的叶子节点上。
4.3 插入
用习题学习
4.4 删除
用习题学习
5. 平衡二叉树(AVL树)
一个概念:
平衡因子:左子树高度 - 右子树高度
平衡二叉树:树中的任意一个节点的左、右子树高度差绝对值不超过1。
5.1 平衡二叉树的调整
RR旋转
图中关注的是“麻烦节点”与“发现节点”之间的位置关系,图上,Nov在Mar右边的右边。具体例子如下: