树的存储结构

如何在计算机中表示一棵树?在介绍树的定义时,我们提到树是元素关系的集合,我们只需要用顺序存储结构链式存储结构把元素之间的关系表示清楚即可。

双亲表示法

在一棵树中,除了根节点外,树中的每个节点有且仅有一个双亲节点。给每个节点增加一个伪指针指示其双亲节点在数组中的位置。这样每个节点不仅知道自己是谁,还知道自己的双亲是谁。

用一个一维的结构体数组来表示一棵树。

结构体数组的单元

通过双亲表示法将逻辑结构映射到存储结构

-1是根节点的标识,表示没有双亲节点。

#define MAXSIZE 100

typedef int ElemType;

typedef struct _ptnode{
    ElemType data;			/* 节点数据域 */
    int parent;				/* 双亲节点的位置*/
}ptnode;

typedef struct _ptree{
    ptnode node[MAXSIZE];	/* 节点数组 */
    int r, n;				/* 根节点的位置和节点 数*/
}ptree;

这样的存储结构,访问双亲节点的时间复杂度为O(1)。

从一个节点往下查找所有的孩子节点时,则需要遍历整个结构,时间复杂度为O(n)。

孩子表示法

在节点中设置多个指针域来指向孩子节点。节点指针域的个数等于树的度

节点逻辑示意图

从逻辑结构映射到存储结构

从图中不难看出,当树中各节点的度相差很大时,节点空间存在很大的浪费。

采用不同的思路,把每个节点的孩子节点排列起来,以单链表作为存储结构,有n个节点就有n个孩子链表,如果是叶子节点则此单链表为空。用一个一维数组来存放n个头指针。
如下

孩子链表的孩子节点示意图

头指针数组元素单元示意图

通过孩子表示法将逻辑结构映射到存储结构

#define MAXSIZE 100

typedef struct _ctnode{
    int child;				/* 孩子在头指针数组的位置 */
    struct _ctnode *next;	/* 下一个孩子节点的位置, 孩子链表里的节点都是兄弟节点 */
}ctnode;

typedef struct _ctbox{
    ElemType data;			/* 存储在数组中的数据域 */
    ctnode *firstChild;		/* 孩子链表的头指针 */
}ctbox;

typedef struct _ctree{
    ctbox node[MAXSIZE];	/* 头指针数组 */
    int r, n;				/* 根节点位置和节点数 */
}ctree;
  • 若以孩子链表的child作为跳转,则按照从左向右的顺序依次访问子树

访问A的firstChild指向的孩子节点,取出child下标,访问头指针数组> 的child位置,再重复上面的动作。遍历顺序是A、B、E

  • 若以孩子链表的next作为跳转,则按照从左到右的顺序依次访问完当前节点所有的孩子节点

孩子兄弟表示法

孩子兄弟表示法的思想是:关注一棵树中一个节点,它的节点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。用两个指针分别指向它的第一个孩子和右兄弟。这样表示之后,双亲节点只知道第一个孩子是谁,第一个孩子知道第二个孩子,第二个孩子知道第三个孩子,以此类推。当双亲节点要去找到第三个孩子时就通过第一个孩子和第二个孩子即可。

孩子兄弟表示法的节点

通过孩子兄弟表示法将逻辑结构映射到存储结构

typedef struct _cstnode{
    ElemType data;					/* 节点数据域 */
    struct _cstnode *firstChild;	/* 第一个孩子节点指针域 */
    struct _cstnode *nextSib;		/* 兄弟节点指针域 */
}cstnode;

如果我们将孩子兄弟法的存储结构旋转45° 能得到下面这幅图
在这里插入图片描述
从图中不难发现,树中的每个节点的度最大为2,该树是一个二叉树

可见,一般的树都可以用孩子兄弟表示法用二叉树的方式来实现。

©️2020 CSDN 皮肤主题: 护眼 设计师:闪电赇 返回首页