c#数据结构(4.2树与森林)

一,树的存储

       在实际应用中,人们采用多种形式的存储结构来表示树, 既有顺序存储结构又有链式存储结构,但无论采用哪种存储结构,都要求存储结构不但能存储结点本身的信息,还能存储树中各结点之间的逻辑关系。下面介绍几种常用的树的存储方式。

         1、双亲表示法从树的定义可知,除根结点外,树中的每个结点都有唯一的一个 双亲结点。根据这一特性,可用一组连续的存储空间(一维数组)存储树中的各结点。树中的结点除保存结点本身的信息之外,还要保存其双亲结点在数组中的位置(数组的序号),树的这种表示法称为 双亲表示法
        由于树的结点只保存两个信息,所以树的结点用结构体 PNode来表示。结构中有两个字段:数据字段 data 和双亲位置字段 pPos。而树类 PTree只有一个成员数组字段 nodes,用于保存结点。PNode和 PTree都只给出了成员字段,没有给出其它成员,比如属性、构造器、成员方法等等,感兴趣的读者可以自己添加。
         树的双亲表示法的结点的结构如下所示:

                                                                

         图 5.1 所示的树的双亲表示法如图 5.12 所示。图中 pPos 域的值为-1 表示该结点是根结点,无双亲结点。

                         

                                                                                                                               图5.1

二,树、森林与二叉树的转换

       从树的孩子兄弟表示法可知,树可以用二叉链表进行存储,所以,二叉链表可以作为树和二叉树之间的媒介。也就是说,借助二叉链表,树和二叉树可以 相互进行转换
       从物理结构来看,它们的二叉链表是相同的,只是解释不同而已。并且,如果设定一定的规则,就可用二叉树来表示森林,森林和二叉树也可以相互进行转换。
        1、树转换为二叉树
        由于二叉树是有序的,为了避免混淆,对于无序树,我们约定树中的每个结点的孩子结点按从左到右的顺序进行编号。如图 5.1 所示的树,根结点 A 有三个孩子 B、C、D,规定结点 B 是结点 A 的第一个孩子,结点 C 是结点 A 的第 2个孩子,结点 D 是结点 A 的第 3 个孩子。
         将树转换成二叉树的步骤是:
(1) 加线。就是在所有兄弟结点之间加一条连线;
(2) 抹线。就是对树中的每个结点,只保留他与第一个孩子结点之间的连线,删除它与其它孩子结点之间的连线;
(3) 旋转。就是以树的根结点为轴心,将整棵树顺时针旋转一定角度,使之结构层次分明。
                                      
              2、森林转换为二叉树
             森林是由若干棵树组成,可以将森林中的每棵树的根结点看作是兄弟,由于每棵树都可以转换为二叉树,所以森林也可以转换为二叉树。
            将森林转换为二叉树的步骤是:
(1)先把每棵树转换为二叉树;
(2)第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树的根结点的右孩子结点,用线连接起来。当所有的二叉树连接起来后得到的二叉树就是由森林转换得到的二叉树。
             图 5.16 是森林转换为二叉树的转换过程示意图。

                                     

                    3、二叉树转换为树

                      二叉树转换为树是树转换为二叉树的逆过程,其步骤是:

(1)若某结点的左孩子结点存在,将左孩子结点的右孩子结点、右孩子结点的右孩子结点……都作为该结点的孩子结点,将该结点与这些右孩子结点用线连接起来;

(2)删除原二叉树中所有结点与其右孩子结点的连线;

(3)整理(1)和(2)两步得到的树,使之结构层次分明。

     图 5.17 是二叉树转换为树的过程示意图。

                                   

       4、二叉树转换为森林

       二叉树转换为森林比较简单,其步骤如下:

(1)先把每个结点与右孩子结点的连线删除,得到分离的二叉树;

(2)把分离后的每棵二叉树转换为树;

(3)整理第(2)步得到的树,使之规范,这样得到森林。

三,树和森林的遍历

1、树的遍历
       树的遍历通常有两种方式。
(1) 先序遍历,即先访问树的根结点,然后依次先序遍历树中的每棵子树。
(2) 后序遍历,即先依次后序遍历树中的每棵子树,然后访问根结点。
       对图 5.1 所示的树进行先序遍历所得到的结点序列为:
                          A B E F G C H D I J
       对此树进行后序遍历得到的结点序列为:
                          E F G B H C I J D A
       根据树与二叉树的转换关系以及二叉树的遍历定义可以推知,树的先序遍历与其转换的相应的二叉树的先序遍历的结果序列相同;树的后序遍历与其转换的二叉树的中序遍历的结果序列相同;树的层序遍历与其转换的二叉树的后序遍历的结果序列相同。因此,树的遍历算法可以采用相应的二叉树的遍历算法来实现。
       另外,在后面讲图的广度优先遍历算法中要提到树的层序遍历算法。树的层序遍历算法与二叉树的层序遍历算法类似,也是从树的根结点开始,按从从上到下从左到右的顺序进行遍历。
2、森林的遍历
      森林的遍历有两种方式。
(1) 先序遍历,即先访问森林中第一棵树的根结点,然后先序遍历第一棵树中的每棵子树,最后先序遍历除第一棵树之后剩余的子树森林。
(2) 中序遍历,即先中序遍历森林中第一棵树的根结点的所有子树,然后访问第一棵树的根结点,最后中序遍历除第一棵树之后剩余的子树森林。
      图 5.16(a)所示的森林的先序遍历的结点序列为:
                             A B C D E F G H J I
      此森林的中序遍历的结点序列为:
                             B C D A F E J H I G
      由森林与二叉树的转换关系以及森林与二叉树的遍历定义可知,森林的前序遍历和中序遍历与所转换得到的二叉树的先序遍历和中序遍历的结果序列相同。

                                                                                      (完)

猜你喜欢

转载自blog.csdn.net/qq_40138785/article/details/81065200
今日推荐