【图论】树的基本概念、存储与遍历
树的基本概念、存储与遍历相关内容
基本概念
树:特殊的图
无根树
无根树等价定义:
- 个节点, 条边的连通无向图
- 无向无环的连通图
- 任意两个结点之间有且仅有一条简单路径的无向图
- 任何边均为桥的连通图
- 没有圈,且在任意不同两点间添加一条边之后所得图含唯一的一个圈的图
有根树
有根树:无根树指定一个根节点
- 父节点(父亲)(parent node):对于除根以外的每个结点,定义为从该结点到根路径上的第二个结点。 根结点没有父结点。
- 祖先(ancestor):一个结点到根结点的路径上,除了它本身外的结点。 根结点的祖先集合为空。
- 子结点(孩子)(child node):如果 是 的父亲,那么 是 的子结点。子结点的顺序一般不加以区分(例外:二叉树)
- 兄弟(sibling):同一个父亲的多个子结点互为兄弟。
- 后代(descendant):子节点及其后代
- 子树(subtree):删掉与父亲相连的边后,该结点所在的子图。
相关定义
- 森林(forest):每个连通分量(连通块)都是树的图。按照定义,一棵树也是森林。
- 结点的深度(depth):到根结点的路径上的边数。
- 树的高度(height):所有结点的深度的最大值。
特殊的树
- 链(chain/path graph):满足与任一结点相连的边不超过 条的树称为链。
- 菊花/星星(star):所有节点都与某一个节点相连(除自身)
- 二叉树
- 有根二叉树(rooted binary tree):每个结点最多只有两个孩子的有根树称为二叉树。常常对两个孩子的顺序加以区分,分别称之为左孩子和右孩子。
- 完整二叉树(full/proper binary tree):每个结点的子结点数量均为 0 或者 2 的二叉树。换言之,每个结点或者是树叶,或者左右子树均非空。
- 完全二叉树(complete binary tree):只有最下面两层结点的度数可以小于 2,且最下面一层的结点都集中在该层最左边的连续位置上。
- 完美二叉树(满二叉树)(perfect binary tree):所有叶结点的深度均相同的二叉树称为完美二叉树。
- 平衡二叉树(AVL树):它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
- 生成树(spanning tree):一个连通无向图的生成子图,同时要求是树。也即在图的边集中选择 条,将所有顶点连通。
二叉树计算公式
- 个节点的二叉树一共有 种(Catalan数)
- 二叉树的第 层最多有个节点(以 起计数)
- 表示节点度数为 的节点个数,总节点数 ,由此还可推出
- 个节点的完全二叉树的深度为
存储
无根树
vector存相邻节点最方便,类比图的存法
有根树
一个只存在书上的左孩子右兄弟表示法:每个节点记录第一个孩子节点 和下一个兄弟节点 ,跟链式前向星一样的
1 | //遍历 |
二叉树
- 数组:左右孩子
- 指针:左右孩子指针,节点值 。
但是作为一个oi是自学c语言上手的人,有一说一,个人觉得指针表示法确实清晰,但确实不利好oi
遍历
二叉树
先序遍历
根+左子树+右子树
1 | void dfs (int u) |
中序遍历
左子树+根+右子树
1 | void dfs (int u) |
后序遍历
左子树+右子树+根
1 | void dfs (int u) |
二叉树特性
知中序+前/后序可知另一个:
- 前序序列第一个是根,后序序列最后一个是根
- 每个子树看成一颗新树
1 | //已知中序后续求先序 |
也就是可以求出这棵树了,以后序+中序为例
1 | int tree[N][2]; // tree[i][0/1]是左右子树的节点编号,空置-1 |
已知前序后序,中序不唯一
- 观察可知,造成不唯一的原因是一棵子树只有一个子节点,即前序:根+子,后续:子+根
- 只需要统计这样的子树有 个,答案是 (可能左可能右)
1 | char inorder[N]; |
无根树
1 | void dfs(int u, int from) |