树基础
树定义
考虑一个有 $n$ 个节点,$n-1$ 条边的无向连通图,任取两个节点有且仅有一条简单路径,考虑这种图为无根树。
在此基础上,指定某一个节点为根节点,节点之间出现了层级关系,称之为有根树
之后的讨论都基于有根树,简称有根树为树
树概念
对于树上的某个非根节点 $N$,定义其(唯一的)直接前驱为父节点,将 $N$ 与父节点断开后,剩余的以 $N$ 为根节点的树称为 $N$ 的子树;
如果一个节点的父节点是 $N$,那么该节点为 $N$ 的子节点;一个父节点可以有多个子节点,这些并列关系的子节点互相为兄弟节点;
某个节点的子节点个数称为该节点的度,所有节点的度的最大值称为树的度;
度为 0 的节点称为叶节点,度不为 0 的节点称为分支节点
定义混乱的一些定义
节点的高度定义为:叶节点的高度为 1;一个节点的父节点高度为该节点高度加 1;树的高度为根节点的高度
节点的深度定义为:根节点的深度为 1;一个节点的子节点深度为该节点深度加 1;树的高度为所有节点的深度的最大值
规定节点的层次和节点的深度等价;规定根节点的深度与层次均为 1
如果一棵树需要关心各个节点子树的顺序,那么这类数为有序树,否则为无序树
典型的有序树例子为二叉树,其严格要求左右子树的顺序
树抽象
一个存储信息较为完整的树可以构造出这些常用的函数
1 2 3 4 5 6 7 8 9 10 11 12 | |
树存储
存储父节点
因为任意节点的父节点唯一,所以用一维数组即可储存,只适用于自底向上的遍历
1 2 | |
在涉及树的自底向上递推 / DP 等操作,以及并查集构造中,这一存储方式简单实用
存储子节点
因为任意节点的子节点不唯一,所以用二维邻接表储存,只适用于自顶向下的遍历
1 2 | |
通常来说,将二维数组 adj 和一维数组 parent 结合使用,就可以较好地存储一张有向树
“左孩子右兄弟”
我们发现邻接表的存储方案用到了开销大的二维数组,并且如果需要访问一个节点的兄弟节点,需要先访问父节点,再访问父节点对应的邻接表
这里有一种内存开销更小的方案:
1 2 | |
如果需要自底向上遍历可以直接加上 parent 数组
不难发现通过这种存储方式,我们将任意的多叉树转化为了二叉树的存储(任何节点都只有 “下一个兄弟节点” 和 “第一个子节点” 两个分叉),因此可以直接对任意多叉树使用二叉树算法,并且将各种树形结构统一化存储
容易得到多叉树和这种存储方式得到的二叉树之间存在双向的转换