作者:成就未来7368 | 来源:互联网 | 2024-10-16 10:44
树的存储结构1.双亲表示法这种方法用一组连续的空间来存储树中的结点,在保存每个结点的同时附设一个指示器来指示其双亲结点在表中的位置,其结点的结构如下图所示:双亲表示法的形式说明如下
- 这种方法用一组连续的空间来存储树中的结点,在保存每个结点的同时附设一个指示器来指示其双亲结点在表中的位置,其结点的结构如下图所示:
双亲表示法的形式说明如下:
#define MAX 100
typedef struct TNode
{
DataType data;
int parent;
} TNode;
树可以定义为:
typedef struct
{
TNode tree[MAX];
int nodenum; /*结点数*/
} ParentTree;
- 这种方法通常是把每个结点的孩子结点排列起来,构成一个单链表,称为孩子链表。n 个结点共有 n 个孩子链表(叶子结点的孩子链表为空表),而 n 个结点的数据和 n 个孩子链表的头指针又组成一个顺序表。
孩子表示法的存储结构定义如下:
typedef struct ChildNode /* 孩子链表结点的定义 */
{
int Child; /* 该孩子结点在线性表中的位置 */
struct ChildNode *next; /*指向下一个孩子结点的指针 */
} ChildNode;
typedef struct /* 顺序表结点的结构定义 */
{
DataType data; /* 结点的信息 */
ChildNode *FirstChild; /* 指向孩子链表的头指针 */
} DataNode;
typedef struct /* 树的定义 */
{
DataNode nodes[MAX]; /* 顺序表 */
int root; /* 该树的根结点在线性表中的位置 */
int num; /* 该树的结点个数 */
} ChildTree;
- 这种表示法又称为树的二叉表示法,或者二叉链表表示法,即以二叉链表作为树的存储结构。链表中每个结点设有两个链域,分别指向该结点的第一个孩子结点和下一个兄弟(右兄弟)结点。
孩子兄弟表示法的类型定义如下:
typedef struct CSNode
{
DataType data; /*结点信息*/
Struct CSNode *FirstChild; /*第一个孩子*/
Struct CSNode *Nextsibling; /*下一个兄弟*/
} CSNode, *CSTree;
这种存储结构便于实现树的各种操作,例如,如果要访问结点 x 的第 i 个孩子,则只要先从FirstChild 域找到第一个孩子结点,然后沿着这个孩子结点的 Nextsibling 域连续走 i-1 步,便可找到 x的第 i 个孩子。如果在这种结构中为每个结点增设一个 Parent 域,则同样可以方便地实现查找双亲的操作。
前面介绍了树的存储结构和二叉树的存储结构,从中可以看到,树的孩子兄弟链表结构与二叉树的二叉链表结构在物理结构上是完全相同的,只是它们的逻辑含义不同,所以树和森林与二叉树之间必然有着密切的关系。本节介绍树和森林与二叉树之间的相互转换方法。
- 森林是若干棵树的集合。树可以转换为二叉树,森林同样也可以转换为二叉树。因此,森林也可以方便地用孩子兄弟链表表示。
方法一:
void RootFirst(CSTree root)
{
if (root != NULL)
{
Visit(root->data); /* 访问根结点 */
p = root->FirstChild;
while (p != NULL)
{
RootFirst(p); /* 访问以 p 为根的子树 */
p = p->Nextsibling;
}
}
}
方法二:
void RootFirst(CSTree root)
{
if (root != NULL)
{
Visit(root->data); /*访问根结点*/
RootFirst(root->FirstChild); /*先根遍历首子树*/
RootFirst(root->Nextsibling); /*先根遍历兄弟树*/
}
}
例如,右图中森林的后序遍历序列为 DCBFJIHGEA。
对照二叉树与森林之间的转换关系可以发现,森林的先序遍历、中序遍历和后序遍历与其相应二叉树的先序遍历、中序遍历和后序遍历是对应相同的,因此可以用相应二叉树的遍历结果来验证森林的遍历结果。另外,树可以看成只有一棵树的森林,所以树的先根遍历和后根遍历分别与森林的先序遍历和中序遍历对应。森林的遍历算法可以采用其对应的二叉树的遍历算法来实现。