双亲表示法
- 双亲存储结构是一种顺序存储结构,用一组连续空间存储树的所有结点,同时在每个结点中附设一个伪指针指示其双亲结点的位置(因为除了根结点以外,每个结点只有唯一的双亲结点,将根结点的双亲结点位置设置为特殊值-1)。

- 优点:查指定结点的双亲很方便。
- 缺点:查指定结点的孩子只能从头遍历。
双亲存储结构的类型声明
#define MAX_TREE_SIZE 100
typedef struct
{
ElemType data;
int parent;
}PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE];
int n;
}PTree;
增加一个结点
- 只需在空白处写入新结点的值并且记录它和双亲的关系。
- 新增的数据元素无需按逻辑上的次序存储。
删除一个结点
- 方案一:将要删除的结点的双亲结点的“指针”设为-1,这就表示该位置是空的。(空数据会导致遍历过程更慢)
- 方案二:把尾部的数据往上移,填充要删除的那一行的数据。

区别树的顺序存储结构与二叉树的顺序存储结构
- 在树的顺序存储结构中,数组下标代表结点的编号,下标中所存的内容指示了结点之间的关系。而在二叉树的顺序存储结构中,数组下标既代表了结点的编号,又指示了二叉树中各结点之间的关系。当然二叉树属于树,因此二叉树都可以用树的存储结构来存储,但树却不都能用二叉树的存储结构来存储。
代码实现
#include<stdio.h>
#define MAX_TREE_SIZE 100
#define NodeNum 13
typedef char ElemType;
typedef struct
{
ElemType data;
int parent;
}PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE];
int n;
}PTree;
void CreateTree(PTree& t)
{
int i, loc;
ElemType ch;
for (i = 0; i < NodeNum; i++)
{
printf("输入结点信息:");
scanf("%c", &ch);
scanf("%c", &ch);
t.nodes[i].data = ch;
printf("输入对应双亲的位置下标:");
scanf("%d", &loc);
t.nodes[i].parent = loc;
printf("\n");
}
}
int main()
{
PTree t;
int i, j;
CreateTree(t);
printf("输出各结点的连接情况:\n");
for (i = 0; i < NodeNum; i++)
{
printf("%c", t.nodes[i].data);
for (j = 0; j < NodeNum; j++)
{
if (t.nodes[j].parent == i) printf(" -%c", t.nodes[j].data);
}
printf("\n");
}
return 0;
}
运行结果


孩子表示法
孩子链存储结构的类型声明
typedef struct
{
int child;
struct CTNode *next;
}CTNode;
typedef struct
{
ElemType data;
struct CTNode *firstChild;
}CTBox;
typedef struct
{
CTBox nodes[MAX_TREE_SIZE];
int n,r;
}CTree;
按各个结点的度设计结构
- 孩子表示法是将每个结点的孩子结点都用单链表链接起来形成一个线性结构,此时n个结点就有n个孩子链表(叶子结点的孩子链表为空表)。

- 优点:寻找子女的操作非常直接
- 缺点:寻找双亲的操作需要遍历n个结点中孩子链表指针域所指向的n个孩子链表。
代码实现
#include<stdio.h>
#include<malloc.h>
#define MAX_TREE_SIZE 100
#define NodeNum 11
typedef char ElemType;
typedef struct CTNode
{
int child;
struct CTNode* next;
}CTNode;
typedef struct
{
ElemType data;
struct CTNode* firstChild;
}CTBox;
typedef struct
{
CTBox nodes[MAX_TREE_SIZE];
int n, r;
}CTree;
void CreateBox(CTree &t)
{
int i;
ElemType ch;
printf("输入结点信息:");
for (i = 0; i < NodeNum; i++)
{
scanf("%c", &ch);
t.nodes[i].data = ch;
t.nodes[i].firstChild = NULL;
}
}
void CreateNodes(CTree& t,ElemType ch, int num)
{
CTNode* p, * r = t.nodes[0].firstChild;
int i, j, k;
while (num--)
{
p = (CTNode*)malloc(sizeof(CTNode));
p->next = NULL;
printf("输入孩子结点的编号:");
scanf("%d", &i);
for (j = 0; j < NodeNum; j++)
if (t.nodes[j].data == ch) k = j;
if (i != k)
{
p->child = i;
if (t.nodes[k].firstChild == NULL)
{
t.nodes[k].firstChild = p;
r = p;
}
else
{
r->next = p;
r = p;
}
}
}
}
int main()
{
CTree t;
CTNode* p;
int i, num;
CreateBox(t);
printf("\n");
for (i = 0; i < NodeNum; i++)
{
printf("创建结点%c的孩子结点\n", t.nodes[i].data);
printf("输入要创建的孩子结点个数:");
scanf("%d", &num);
CreateNodes(t, t.nodes[i].data, num);
printf("\n");
}
printf("输出各结点的连接情况:\n");
for (i = 0; i < NodeNum; i++)
{
p = t.nodes[i].firstChild;
printf("%d(%c)", i, t.nodes[i].data);
while (p != NULL)
{
printf("-%d(%c) ", p->child, t.nodes[p->child].data);
p = p->next;
}
printf("\n");
}
return 0;
}
运行结果
