1 双亲表示法(方便查找双亲)
使用层次遍历的方法将一个树中的所有结点存储到一维数组中
2 孩子表示法(方便查找孩子)
顺序+链式存储结构:
1 使用数组来存储所有结点
2 为每一个结点来设置一个单链表
3 单链表链接的是其所有孩子结点的下标
3 双亲孩子结合表示法
在孩子表示法的数组中增加一个parent区域
4 孩子兄弟表示法(左孩子右兄弟表示法)
**使用二叉链表作为树的存储结构**
firstChild指向结点最左侧的第一个孩子
nextSibling指向结点右侧的紧挨着的第一个兄弟
5 树到二叉树的转换
5.1 将树转化为二叉树
(将树转化为二叉树其右子树一定为空)
5.1.1连线
在所有的兄弟结点之间加上一条连线
5.1.2删线
对于每个结点,除了保留与其最左孩子的连线外,删掉该结点与其它孩子之间的连线
5.1.3旋转
将按照以上方法形成的二叉树,沿着顺时针方向旋转45°
就可以得到一颗二叉树
6 森林到二叉树的转换
6.1 将森林转化为二叉树
6.1.1连线
在所有的兄弟结点之间加上一条连线
(包括森林中所有树的根节点)
6.1.2删线
对于每个结点,除了保留与其最左孩子的连线外,删掉该结点与其它孩子之间的连线
6.1.3旋转
将按照以上方法形成的二叉树,沿着顺时针方向旋转45°
就可以得到一颗二叉树
7 二叉树到森林或树的转换
是森林或树到二叉树的转换的逆过程
注意:
1 连线:如果某结点的左孩子有右子树,将该结点**与其左孩子的右子树的右链上各个结点都增加连线**
2 删线:删除二叉树中所有双亲结点与其右孩子结点的连线
8 树和森林的遍历
8.1 树和森林的深度优先遍历
注意:
1 树的前序遍历和对应二叉树的前序遍历一样
2 树的中序(后序)遍历和对应二叉树的中序遍历一样
8.1.1 前序遍历
//实现树和森林的前序遍历
void func_qxbl(Node* t){
while(t!=NULL)
{
printf("%d\n",t->data);//访问当前结点数据
func_qxbl(t->firstChild);//前序遍历t的各个子树
t = t->nextSibling;//遍历其他的树
}
}
8.1.2 中序(也叫后序)遍历
//实现树和森林的中序(后续)遍历
void func_zhxbl(Node* t){
while(t!=NULL)
{
func_zhxbl(t->firstChild);//遍历t的各个子树
printf("%d\n",t->data);//访问当前结点数据
t = t->nextSibling;//遍历其他的树
}
}
8.1.3 总结
因为:
1 树的前序遍历和对应二叉树的前序遍历一样
2 树的中序(后序)遍历和对应二叉树的中序遍历一样
3 那么树的前序遍历代码可以写成对应二叉树的前序遍历代码
4 树的中序(后序)遍历代码可以写成对应二叉树的中序遍历代码
利用二叉树的前序遍历实现树、森林的前序遍历
void func_qxbl(Node* t){
if(t!=NULL)
{
printf("%d\n",t->data);//访问当前结点数据
func_qxbl(t->firstChild);//前序遍历第一棵子树
func_qxbl(t->nextSibling);//前序遍历其他子树
}
}
利用二叉树的中序遍历实现树、森林的中序(后序)遍历
void func_zhxbl(Node* t){
if(t!=NULL)
{
func_zhxbl(t->firstChild);//遍历第一棵子树
printf("%d\n",t->data);//访问当前结点数据
func_zhxbl(t->nextSibling);//遍历其他子树
}
}
8.2 树和森林的广度优先遍历
8.2.1 层次遍历(从上到下、从左到右)
9 求树的高度
注意:
1 树和森林采用左孩子右兄弟表示法(二叉树)
使用递归前序遍历树
int height(){
if(t == NULL)
return 0;
else{
int lh = height(t->firstChild);
int rh = height(t->nextSibling);
return 1+lh>rh?lh+1:rh;
// 1+lh是t这棵树的高度
// rh是兄弟森林的高度
}
}
10 求树的结点总数
使用递归前序遍历树
int size(Node* t){
if(t == NULL)
return 0;
else
return 1+size(t->firstChild)+size(t->nextSibling);
}
11 求树的叶子结点总数
使用递归前序遍历树
int leaf(Node* t)
{
if(t == NULL)
return 0;
else{
if(t->firstChild == NULL)//当前结点是叶子结点
return 1+leaf(t->nextSibling);
else
return leaf(t->firstChild)+leaf(t->nextSibling);
}
}
12 典型题目解析
解析:
1 根据二叉树画出森林
2 判断对应关系
结论:
1 u和v可能具有的关系是:父子关系、兄弟关系
解析:
1 根据二叉树的性质:n0 = n2+1 可得
2 对于度为4的树而言:n0 = 3*n4+2*n3+1*n2+1
3 n0 = 60+20+1+1 = 82个
解析:
1 树和森林使用的是孩子兄弟表示法
2 如果左孩子指针为空,就不会有其他孩子了
3 其就是叶子结点
4 所以说**森林中叶子结点的个数**对应**二叉树中左孩子指针为空的结点个数**
解析:
1 15条边对应16个结点
2 剩余的9个结点构成9个树
3 1+9 = 10
13 易错题