第八章 解决树和森林的编程问题
树是n个相同类型的有限集合。
树的两个特点:
1) 树的根结点没有前驱结点,除了根结点之外的所有结点有且只有一个前驱结点
2) 树中所有结点有零个或多个后继结点。
树的度:树中各节点度的最大值
无序树:树中任意一个结点的各孩子结点之间的次序构成无关紧要的树。
树的逻辑表示:
1) 直观表示法:整个图就像一棵倒立的树,从根结点出发不断扩展,根结点在最上层,叶子结点在最下面
2) 嵌套结合表示法:一些集合的集体,对于其中任何两个集合,或者相交,或者一个包含另一个。即将根结点视为一个大的集合,其若干棵子树构成这个大集合中若干互不相交的子集,如此嵌套下去,即构成一棵树的嵌套集合表示。
3) 凹入表示法:每个节点对应一个矩形,所有结点的矩形都右对齐,根结点用最长的矩形表示,同一层的结点的矩形长度相同,层次越高,矩形的度越短。
4) 广义表示法:根结点排在最前面,用一对圆括号把它的子树结点括起来,子树结点用逗号隔开,这样依次将树表示出来。
树的存储:
1) 多重链表表示法:由于树中的每个结点都有零个或多个孩子结点,因此可以令每个结点包括一个结点信息域和多个指针域,每个指针域指向该结点的一个孩子结点,通过各个指针域值反映出树中各节点的逻辑关系。
2) 双亲结点表示法:树中的结点除保存结点本身的信息外,还要保存其双亲结点在数组中的位置(数组的序号),树的这种表示法称为双亲表示法。
3) 用孩子链表表示法:用一维数组来存储树中各结点的信息。但结点的结构与双亲表示法中结点的结构不同,孩子链表表示法中结点除保存本身的信息外,不是保存其双亲结点在数组中的序号,而是保存一个链表的第一个结点的地址信息。这个链表是由该结点的所有孩子结点组成,每个孩子结点保存两个信息,一个是每个孩子结点在一维数组中的序号,另一个是下一个孩子结点的地址信息。
4) 双亲孩子表示法:将双亲表示法和孩子链表表示法相结合。其仍将各结点的孩子结点分别组成单链表,同时用一维数组顺序存储树中的各结点,数组元素除了包括结点本身的信息和该结点的孩子结点链表的头指针之外,还增设一个域,存储该结点双亲结点在数组中的序号。
5)孩子兄弟表示法:又称二叉树表示法,或二叉链表表示法,即以二叉链表作为树的存储结构。每个结点除存储本身的信息外,还有两个应用于分别存储该结点第一个孩子的地址信息和下一个兄弟的地址信息。
树、森林与二叉树的转换
1)树转换为二叉树,算法描述
树中所有相邻兄弟之间加一条连线
对树中的每个结点,只保留它与第一个孩子结点之间的连线,删去它与其他孩子结点之间的连线
以树的根结点为轴心,将整棵树顺时针转动一定角度,使之结构层次分明。
在二叉树中,左分支上的各结点在原来的树中是父子关系,而右分支上的结点在原来的树中是兄弟关系。由于树的根结点没有兄弟,所以变换后的二叉树的根结点的右孩子比为空。示例如下:
2)森另转换为二叉树,算法描述:
将森林中的每棵树转换为对应的二叉树
第一棵二叉树不动,从第二棵二叉树开始,一次把后一棵树的根结点作为前一棵树根结点的右孩子,当所有的二叉树连接起来后,此时得到的二叉树就是由森林转换的二叉树
3)二叉树转换为树和森林:
若某结点是其双亲的左孩子,则把该结点的右孩子,右孩子的右孩子……都与该结点的双亲结点用线连接起来
删去原二叉树中的所有的双亲结点与右孩子结点的连线
整理由前两步所得到的树或森林,使之层次分明
示例如下:
树的遍历:
先序遍历:
1) 访问树的根结点
2) 按从左到右顺序先序遍历树中的每棵子树
后序遍历:
1) 按从左到右顺序先序遍历树中的每棵子树
2) 访问树的根结点
层次遍历:按照树的结构从上到下、从左到右的顺序访问树的结点。
森林的遍历
先序遍历:
1) 访问森林中的第一棵树的根结点
2) 先序遍历第一棵树中的每棵子树
3) 先序遍历除第一棵树之后剩余的子树森林
中序遍历
1) 中序遍历森林中的第一棵树的根结点的所有子树
2) 访问第一棵树的根结点
3) 中序遍历除第一棵树之后剩余的子树森林