术语
- 节点的度:一个节点含有的子树的个数称为该节点的度;
- 树的度:一棵树中,最大的节点的度称为树的度;
- 叶节点或终端节点:度为零的节点;
- 非终端节点或分支节点:度不为零的节点;
- 父亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
- 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
- 兄弟节点:具有相同父节点的节点互称为兄弟节点;
- 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
- 树的高度或深度:树中节点的最大层次;
- 堂兄弟节点:父节点在同一层的节点互为堂兄弟;
- 节点的祖先:从根到该节点所经分支上的所有节点;
- 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
- 森林:由m(m>=0)棵互不相交的树的集合称为森林;
树的种类
- 无序树:树中任意节点的子节点之间没有顺序关系,这种树称为无序树,也称为自由树;
- 有序树:树中任意节点的子节点之间有顺序关系,这种树称为有序树;
存储
父节点表示法
存储结构
/* 树节点的定义 */
#define MAX_TREE_SIZE 100
typedef struct
{
TElemType data;
int parent; /* 父节点位置域 */
} PTNode;
typedef struct
{
PTNode nodes[MAX_TREE_SIZE];
int n; /* 节点数 */
} PTree;
基本操作
设已有链队列类型LinkQueue的定义及基本操作(参见队列)。
构造空树
清空或销毁一个树也是同样的操作
void ClearTree(PTree *T)
{
T->n = 0;
}
构造树
void CreateTree(PTree *T)
{
LinkQueue q;
QElemType p,qq;
int i=1,j,l;
char c[MAX_TREE_SIZE]; /* 临时存放孩子节点数组 */
InitQueue(&q); /* 初始化队列 */
printf("请输入根节点(字符型,空格为空): ");
scanf("%c%*c",&T->nodes[0].data); /* 根节点序号为0,%*c吃掉回车符 */
if(T->nodes[0].data!=Nil) /* 非空树 */
{
T->nodes[0].parent=-1; /* 根节点无父节点 */
qq.name=T->nodes[0].data;
qq.num=0;
EnQueue(&q,qq); /* 入队此节点 */
while(i<MAX_TREE_SIZE&&!QueueEmpty(q)) /* 数组未满且队不空 */
{
DeQueue(&q,&qq); /* 节点加入队列 */
printf("请按长幼顺序输入节点%c的所有孩子: ",qq.name);
gets(c);
l=strlen(c);
for(j=0;j<l;j++)
{
T->nodes[i].data=c[j];
T->nodes[i].parent=qq.num;
p.name=c[j];
p.num=i;
EnQueue(&q,p); /* 入队此节点 */
i++;
}
}
if(i>MAX_TREE_SIZE)
{
printf("节点数超过数组容量\n");
exit(OVERFLOW);
}
T->n=i;
}
else
T->n=0;
}
判断树是否为空
Status TreeEmpty(PTree *T)
{ /* 初始条件:树T存在。操作结果:若T为空树,则返回TRUE,否则返回FALSE */
return T->n==0;
}
获取树的深度
int TreeDepth(PTree *T)
{ /* 初始条件:树T存在。操作结果:返回T的深度 */
int k,m,def,max=0;
for(k=0;k<T->n;++k)
{
def=1; /* 初始化本节点的深度 */
m=T->nodes[k].parent;
while(m!=-1)
{
m=T->nodes[m].parent;
def++;
}
if(max<def)
max=def;
}
return max; /* 最大深度 */
}
获取根节点
TElemType Root(PTree *T)
{ /* 初始条件:树T存在。操作结果:返回T的根 */
int i;
for(i=0;i<T->n;i++)
if(T->nodes[i].parent<0)
return T->nodes[i].data;
return Nil;
}
获取第i个节点的值
TElemType Value(PTree *T,int i)
{ /* 初始条件:树T存在,i是树T中节点的序号。操作结果:返回第i个节点的值 */
if(i<T->n)
return T->nodes[i].data;
else
return Nil;
}
改变节点的值
Status Assign(PTree *T,TElemType cur_e,TElemType value)
{ /* 初始条件:树T存在,cur_e是树T中节点的值。操作结果:改cur_e为value */
int j;
for(j=0;j<T->n;j++)
{
if(T->nodes[j].data==cur_e)
{
T->nodes[j].data=value;
return OK;
}
}
return ERROR;
}
获取节点的父节点
TElemType Parent(PTree *T,TElemType cur_e)
{ /* 初始条件:树T存在,cur_e是T中某个节点 */
/* 操作结果:若cur_e是T的非根节点,则返回它的父节点,否则函数值为"空"*/
int j;
for(j=1;j<T->n;j++) /* 根节点序号为0 */
if(T->nodes[j].data==cur_e)
return T->nodes[T->nodes[j].parent].data;
return Nil;
}
获取节点的最左孩子节点
TElemType LeftChild(PTree *T,TElemType cur_e)
{ /* 初始条件:树T存在,cur_e是T中某个节点 */
/* 操作结果:若cur_e是T的非叶子节点,则返回它的最左孩子,否则返回"空"*/
int i,j;
for(i=0;i<T->n;i++)
if(T->nodes[i].data==cur_e) /* 找到cur_e,其序号为i */
break;
for(j=i+1;j<T->n;j++) /* 根据树的构造函数,孩子的序号>其父节点的序号 */
if(T->nodes[j].parent==i) /* 根据树的构造函数,最左孩子(长子)的序号<其它孩子的序号 */
return T->nodes[j].data;
return Nil;
}
获取节点的右兄弟节点
TElemType RightSibling(PTree *T,TElemType cur_e)
{ /* 初始条件:树T存在,cur_e是T中某个节点 */
/* 操作结果:若cur_e有右(下一个)兄弟,则返回它的右兄弟,否则返回"空"*/
int i;
for(i=0;i<T->n;i++)
if(T->nodes[i].data==cur_e) /* 找到cur_e,其序号为i */
break;
if(T->nodes[i+1].parent==T->nodes[i].parent)
/* 根据树的构造函数,若cur_e有右兄弟的话则右兄弟紧接其后 */
return T->nodes[i+1].data;
return Nil;
}
输出树
void Print(PTree *T)
{ /* 输出树T。加 */
int i;
printf("节点个数=%d\n",T->n);
printf(" 节点 父节点\n");
for(i=0;i<T->n;i++)
{
printf(" %c",Value(T,i)); /* 节点 */
if(T->nodes[i].parent>=0) /* 有父节点 */
printf(" %c",Value(T,T->nodes[i].parent)); /* 父节点 */
printf("\n");
}
}