Skip to content

Chapter 06 树

1. 树的定义

树是包括n个结点的有限集合 T(n≥1),使得:

  • 一个根结点
  • 除根以外的其它结点被分成m个(m≥0)不相交的集合T1,T2,…,Tm,而且这些集合的每一个又都是树。 树T1,T2,…,Tm称作这个根的子树

四种表示法:

1.1 有序树

把树结点的子结点按从左到右的次序编号.

Warning

度小于等于 2 的有序树并不一定是二叉树

这是因为树的孩子不区分左右, 当第 1 子节点被删除后, 第 2 子节点自动称为第 1 子节点. 但是二叉树中删除左子树后右子树不能替代左子树.

只有严格区分左右两个子节点的有序树才是二叉树.

1.2 森林

零棵或多棵不相交的树的集合.

2. 森林与二叉树的等价转换

2.1 森林->二叉树

转换过程:
- 兄弟之间加线 (森林之间的根也加线)
- 从第二个子结点开始断开与父结点的边
- 适当旋转为二叉树

2.2 二叉树->森林

转换过程即为森林->二叉树的逆过程.

  • 加线: 若p结点是父结点的左孩子,则将p的右孩子,右孩子的右孩子,……沿分支找到的所有右孩子,都与p的双亲用线连起来
  • 删线: 删除所有结点和右孩子的连线.
  • 适当旋转.

Tips

对于森林, 可以看作增加一个虚点, 虚点向森林中每一棵树的根连线.

3. 树的周游

3.1 先根次序

若树非空,则遍历方法为:
- 访问根结点
- 从左到右,依次先根遍历根结点的每一棵子树

3.2 后根次序

若树非空,则遍历方法为:
- 从左到右,依次后根遍历根结点的每一棵子树
- 访问根结点

3.3 周游性质

按先根次序周游树正好等于对应二叉树的前序周游

按后根次序周游树正好等于对应二叉树的中序周游

4. 树的链式存储

4.1 子结点表示法

4.2 动态结点表示法

4.3 左孩子右兄弟法


本质上,是使用二叉树来替换树

优点: 每个结点所需空间一致.

4.4 父指针表示法

5. 树的顺序存储

5.1 带右链的先根次序表示法

核心观察:
- 先序遍历中, 子树的所有结点连续排列.
- 如果一个结点有子节点, 先序遍历中该结点的后一个结点一定是它的第一个子结点.

因此, 可以使用一个 ltag 标记是否有子节点. 0 表示有子节点, 1 表示无子节点 (这一点非常反常), 且先序遍历中下一个结点就是第一个子结点. 再用 rlink 指向该结点的下一个兄弟, 这样就实现了左孩子右兄弟表示法. 用 0/1 代替 llink 节省了空间.

5.2 带双标记位的先根次序表示法

事实上, 带右链的先根次序表示法中的 rlink 也不是必须的.

我们使用 rtag 标记. rtag 为 1 表示无兄弟, rtag 为 0 表示有兄弟 (这一点非常反常)

  • 当一个结点x的rtag为1时,它的rlink显然应为空

  • 当一个结点x的rtag为0时,它的rlink应指向结点序列中排在以结点x为根的子树中最后结点的后面的那个结点y

有兄弟的结点(rtag=0),都唯一对应一个无孩子的结点(ltag=1),成对出现,满足栈特性,即

  • 扫描到一个rtag为0的结点就将它进栈
  • 扫描到一个ltag为1的结点就从栈顶弹出一个结点,并为其设置rlink,下一个要读出的节点即为其兄弟节点

5.3 带度数的后根次序表示法


5.4 带双标记的层次次序表示

顺序扫描带双标记的层次次序序列

  • 如果结点的ltag值为1,则置其llink为空;当结点的ltag为0时,该结点入队列;

  • 如果结点的rtag值为0,那么其后的结点y就是其右兄弟;

  • 否则,如果结点的rtag值为1,则rlink为空,此时出队列x,并将x的llink指向序列中后续结点 y即可。