树的存储结构

时间:2020-12-13 13:00:48

1、顺序存储结构:用一段地址连续的存储单元依次存储数据元素。

---- 树中某个结点的孩子可以有多个,这就意味着,无论按何种(顺序存储结构)顺序将树中所有结点存储到数组中,结点的

存储位置都无法直接反映逻辑关系。所以简单的顺序存储结构是不能满足树的实现要求的

---- 可以充分利用顺序存储和链式存储结构的特点,实现对树的存储结构的表示。

---- 目前主要有3种不同的树的存储结构:双亲表示法、孩子表示法、孩子兄弟表示法。

2、双亲表示法

---- 树这种结构:除了根结点外,其余每个结点,它不一定有孩子,但是有且仅有一个双亲。

---- 双亲表示法是以一组连续的存储空间存储树的结点,同时在每个结点中附设一个指示器指示其双亲结点在链表中的位置

这种存储结构利用率每个结点(根结点除外)只有唯一的双亲的性质。约定根结点的指针域设置为-1.

---- 结构如下图所示:

    树的存储结构

---- 其中data是数据域,存储结点的数据信息。而parent是指针域,存储该结点的双亲在数组中的下标

---- 双亲表示法结点结构定义代码:

#define MAX_TREE_SIZE 100
typedef int TElemType;
typedef struct PTNode //结点结构
{
TElemType data;//结点数据
int parent; //双亲位置
} PTNode;
typedef struct //树结构
{
PTNode nodes[MAX_TREE_SIZE];//结点数组
int r,n;//根的位置和结点数
} PTree;
下图中展示了树的结构和树的双亲表示:

       树的存储结构

---- 这样的存储结构,我们可以根据结点的parent指针很容易找到它的双亲结点,但找孩子结点难。

3、孩子表示法

---- 由于树中每个结点可能有多棵子树,因此可以使用多重链表,即每个结点包含多个指针域,其中每个指针指向一棵子树的

根结点,我们把这种方法叫做多重链表表示法。不过,树的每个结点的度(结点的孩子个数)是不同的。两种方案:

--1)每个结点的指针域的个数等于树的度d。

其结构如下表所示:

    树的存储结构

树的度是各个结点的度的最大值,这种方法对于树中各结点的度相差很大时,空间浪费严重(有很多结点的度小于d),出现许多

空的指针域。如果树的各结点度相差很小时,开辟的空间被充分利用了,这时存储结构的缺点就变成了优点。

--2)每个结点指针域的个数等于该结点的度。

需要专门设置一个位置来存储结点指针域的个数,其结构如下表所示:

    树的存储结构

其中data为数据域,degree为度域,就是存储该结点的孩子结点的个数,child1到childd为指针域,指向该结点的各个孩子的结点。

这种方法克服了浪费空间的缺点,但是由于各个结点的链表是不同的结构,还要维护结点的度的数值,运算上损耗时间。

---- 孩子表示法的具体办法是:把每个结点的孩子结点排列起来,以单链表作为存储结构,则n个结点有n个孩子链表,如果是叶子

结点则此单链表为空。然后n个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。

     树的存储结构

为此,设计两种结点结构,一个是孩子链表的孩子结点,如下图所示:

                               树的存储结构

---- 其中child是数据域,用来存储某个结点在表头数组中的下标,next是指针域,用来存储指向某结点的下一个孩子结点的指针。

另一个是表头数组(线性表)的表头结点,如下表所示:

                             树的存储结构

---- 其中data是数据域,存储某结点的数据信息。firstchild是头指针域,存储该结点的孩子链表的头指针。

孩子表示法的结构定义代码如下:

#define MAX_TREE_SIZE 100
typedef int TElemType;
typedef struct CTNode //孩子结点
{
int child;//孩子结点所在下标
struct CTNode * next;
} *ChildPtr;
typedef struct//表头结构
{
TElemType data;
ChildPtr firstchild; //指向孩子结点的指针
} CTBox;
typedef struct //树结构
{
CTBox nodes[MAX_TREE_SIZE];//结点数组
int r,n;//根的位置和结点数
} PTree;
---- 这样的结构对于我们要查找某个结点的某个孩子,或者找某个结点的兄弟,只需要查找这个结点的孩子单链表即可。

对于遍历整棵树也是很方便的,对头结点的数组循环即可。

---- 特点:找双亲难,可以在上面的表头结构中加入结点对应的双亲所在的数组下标。

4、孩子兄弟表示法

---- 孩子兄弟表示法又称作二叉树表示法或二叉链表表示法,即以二叉链表作为树的存储结构。

链表中结点的两个指针分别指向该结点的第一个孩子下一个兄弟结点,结点结构如下表:

           树的存储结构

---- 其中data是数据域,firstchild为指针域,存储该结点的第一个孩子结点的存储地址(指向第一个孩子结点)。

rightsib是指针域,存储该结点的第一个孩子的右兄弟结点的存储地址(指向该兄弟结点)。

---- 结构定义代码如下;

typedef int TElemType;
typedef struct CSNode
{
TElemType data;
struct CSNode * firstchild,*rightsib;
} CSNode,*CSTree;
这种方法实现的示意图如下图所示:

        树的存储结构