CSP-J初赛知识3:树形数据结构
树的定义
若 n 个结点由恰好 n-1 条边连接,且没有环,则这些结点和边构成的是一棵树。
树的特点
- 有一个特定的结点,称为根结点,注意根结点不一定确定。
- 当指定根结点后,每个结点都有唯一的父结点,除了根结点。
- 一个结点可能有若干子结点,没有子结点的结点称为叶结点。
- 树上的所有结点一定“连通”,且没有环。
树的性质
结点的度数
一个结点的子结点的个数。
结点的深度
指的是从根结点到结点 x 的层数,有时从0开始计数,有时从1开始计数。
树的深度(高度)
指的是深度最大的结点的深度。
树上路径
指的是两个结点 x 和 y 在树上连接的一条通路,任意两点在树上的“简单路径”是唯一的。
二叉树
定义
每个结点的子结点均不超过两个的树称之为二叉树。
性质
- 在二叉树的第 i 层上最多有 个结点。
- 若根结点的深度从1计数,则深度为h的二叉树至多有 个点。
- 若根结点的深度从1计数,则具有 n 个结点的二叉树的深度至少是。
- 若叶结点的数量为 m,则 n=m+1。
分类
1. 完全二叉树(Complete Binary Tree)
一棵二叉树,除了最后一层,每一层都放满了结点,且最后一层尽可能靠左放结点。
2. 满二叉树(Full Binary Tree)
一棵二叉树,对于任意一个结点,要么有2个子结点,要么没有子结点。
3. 完美二叉树(Perfect Binary Tree)
对于深度为 h 的二叉树,恰好有 个结点,形态上来讲,是所有位置都“放满的”。
二叉树的遍历
用以下这棵树为例:
1. 先序遍历(根、左、右)
first:先访问根结点。
second:递归访问左子树。
third:递归访问右子树。
上图的先序遍历为:cahgfdbe
2. 中序遍历(左、根、右)
first:递归访问左子树。
second:访问根结点。
third:递归访问右子树。
上图的中序遍历为:hgafcdeb
3. 后序遍历(左、右、根)
first:递归访问左子树。
second:递归访问右子树。
third:访问根结点。
4. 层序遍历(一层一层)
从上到下,每一层从左到右访问。
上图的层序遍历为:cadhfbge
由二叉树的遍历确定二叉树的形态
1. 中序遍历+先序遍历
first:由先序遍历确定根结点root,即最开头位置。
second:由中序遍历划分左右子树,root前为左子树,root后为右子树。
third:对每棵子树重复first和second操作,直到确定所有结点。
2. 中序遍历+后序遍历
first:由后序遍历确定根结点root,即最末尾位置。
second:由中序遍历划分左右子树,root前为左子树,root后为右子树。
third:对每棵子树重复first和second操作,直到确定所有结点。
3. 中序遍历+层序遍历
first:层序遍历确定根结点root,即最开头位置。
second:中序遍历划分左右子树
third:对每棵子树重复first和second操作,直到确定所有结点。
树的存储
方法1:父亲表示法
存储每个结点的父结点编号,如
fa[x]=y;
表示x的父结点编号为y。
代码示例
...
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x;
fa[i]=x;
}
...
}
方法2:孩子表示法
存储每个结点的子结点编号,用vector动态数组存,son[x].push_back(y);表示x的子结点编号为y。
代码示例
...
int main()
{
vector<int>son[105];
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>x>>y;//设x为y的父结点
son[x].push_back(y);
}
...
}
方法3:一维数组表示法
若是一棵二叉树,可以用一位数组存,根节点编号设为1,其左子结点为2i,右子结点为2i+1。
树的变形
1. 哈夫曼树
作者的话:
哈夫曼树的延伸
哈夫曼树可以延伸至哈夫曼编码,由于时间不够,下次再具体说明(不是我懒awa)。
其他树
类似的还有平衡树等,由于时间不够,下次再具体说明(不是我懒awa)。
DAY 8 学习日记
今天在其他书上看到了二叉树,可是根本看不懂,没想到下午就讲了,(*^▽^*)