树 (数据结构)

在计算机科学中，树（）是一种抽象数据类型（ADT）或是实作这种抽象数据类型的数据结构，用来模拟具有树状结构性质的数据集合。它是由n（n&gt;0）个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树，也就是说它是根朝上，而叶朝下的。它具有以下的特点：
存储.
父节点表示法.
基本操作.
设已有链队列类型LinkQueue的定义及基本操作（参见队列）。
构造空树.
清空或销毁一个树也是同样的操作
void ClearTree(PTree *T)
 T-&gt;n = 0;
构造树.
void CreateTree(PTree *T)
 LinkQueue q;
 QElemType p,qq;
 int i=1,j,l;
 char c[MAX_TREE_SIZE]; /* 临时存放孩子节点数组 */
 InitQueue(&amp;q); /* 初始化队列 */
 printf("请输入根节点(字符型，空格为空): ");
 scanf("%c%*c",&amp;T-&gt;nodes[0].data); /* 根节点序号为0，%*c吃掉回车符 */
 if(T-&gt;nodes[0].data!=Nil) /* 非空树 */
 T-&gt;nodes[0].parent=-1 ; /* 根节点无父节点 */
 qq.name=T-&gt;nodes[0].data;
 qq.num=0;
 EnQueue(&amp;q,qq); /* 入队此节点 */
 while(i&lt;MAX_TREE_SIZE&amp;&amp;!QueueEmpty(q)) /* 数组未满且队不空 */
 DeQueue(&amp;q,&amp;qq); /* 节点加入队列 */
 printf("请按长幼顺序输入节点%c的所有孩子: ",qq.name);
 gets(c);
 l=strlen(c);
 for(j=0;j&lt;l;j++)
 T-&gt;nodes[i].data=c[j];
 T-&gt;nodes[i].parent=qq.num;
 p.name=c[j];
 p.num=i;
 EnQueue(&amp;q,p); /* 入队此节点 */
 i++;
 if(i&gt;MAX_TREE_SIZE)
 printf("节点数超过数组容量\n");
 exit(OVERFLOW);
 T-&gt;n=i;
 else
 T-&gt;n=0;
判断树是否为空.
Status TreeEmpty(PTree *T)
 return T-&gt;n==0;
获取树的深度.
int TreeDepth(PTree *T)
 int k,m,def,max=0;
 for(k=0;k&lt;T-&gt;n;++k)
 def=1; /* 初始化本节点的深度 */
 m=T-&gt;nodes[k].parent;
 while(m!=-1)
 m=T-&gt;nodes[m].parent;
 def++;
 if(max&lt;def)
 max=def;
 return max; /* 最大深度 */
获取根节点.
TElemType Root(PTree *T)
 int i;
 for(i=0;i&lt;T-&gt;n;i++)
 if(T-&gt;nodes[i].parent&lt;0)
 return T-&gt;nodes[i].data;
 return Nil;
获取第i个节点的值.
TElemType Value(PTree *T,int i)
 if(i&lt;T-&gt;n)
 return T-&gt;nodes[i].data;
 else
 return Nil;
改变节点的值.
Status Assign(PTree *T,TElemType cur_e,TElemType value)
 int j;
 for(j=0;j&lt;T-&gt;n;j++)
 if(T-&gt;nodes[j].data==cur_e)
 T-&gt;nodes[j].data=value;
 return OK;
 return ERROR;
获取节点的父节点.
TElemType Parent(PTree *T,TElemType cur_e)
 /* 操作结果：若cur_e是T的非根节点，则返回它的父节点，否则函数值为＂空＂*/
 int j;
 for(j=1;j&lt;T-&gt;n;j++) /* 根节点序号为0 */
 if(T-&gt;nodes[j].data==cur_e)
 return T-&gt;nodes[T-&gt;nodes[j].parent].data;
 return Nil;
获取节点的最左孩子节点.
TElemType LeftChild(PTree *T,TElemType cur_e)
 /* 操作结果：若cur_e是T的非叶子节点，则返回它的最左孩子，否则返回＂空＂*/
 int i,j;
 for(i=0;i&lt;T-&gt;n;i++)
 if(T-&gt;nodes[i].data==cur_e) /* 找到cur_e，其序号为i */
 break;
 for(j=i+1;j&lt;T-&gt;n;j++) /* 根据树的构造函数，孩子的序号＞其父节点的序号 */
 if(T-&gt;nodes[j].parent==i) /* 根据树的构造函数，最左孩子(长子)的序号＜其它孩子的序号 */
 return T-&gt;nodes[j].data;
 return Nil;
获取节点的右兄弟节点.
TElemType RightSibling(PTree *T,TElemType cur_e)
 /* 操作结果：若cur_e有右(下一个)兄弟，则返回它的右兄弟，否则返回＂空＂*/
 int i;
 for(i=0;i&lt;T-&gt;n;i++)
 if(T-&gt;nodes[i].data==cur_e) /* 找到cur_e，其序号为i */
 break;
 if(T-&gt;nodes[i+1].parent==T-&gt;nodes[i].parent)
 /* 根据树的构造函数，若cur_e有右兄弟的话则右兄弟紧接其后 */
 return T-&gt;nodes[i+1].data;
 return Nil;
输出树.
void Print(PTree *T)
 int i;
 printf("节点个数=%d\n",T-&gt;n);
 printf(" 节点 父节点\n");
 for(i=0;i&lt;T-&gt;n;i++)
 printf(" %c",Value(T,i)); /* 节点 */
 if(T-&gt;nodes[i].parent&gt;=0) /* 有父节点 */
 printf(" %c",Value(T,T-&gt;nodes[i].parent)); /* 父节点 */
 printf("\n");
向树中插入另一棵树.
Status InsertChild(PTree *T,TElemType p,int i,PTree c)
 /* 操作结果：插入c为T中p节点的第i棵子树 */
 int j,k,l,f=1,n=0; /* 设交换标志f的初值为1，p的孩子数n的初值为0 */
 PTNode t;
 if(!TreeEmpty(T)) /* T不空 */
 for(j=0;j&lt;T-&gt;n;j++) /* 在T中找p的序号 */
 if(T-&gt;nodes[j].data==p) /* p的序号为j */
 break;
 l=j+1; /* 如果c是p的第1棵子树，则插在j+1处 */
 if(i&gt;1) /* c不是p的第1棵子树 */
 for(k=j+1;k&lt;T-&gt;n;k++) /* 从j+1开始找p的前i-1个孩子 */
 if(T-&gt;nodes[k].parent==j) /* 当前节点是p的孩子 */
 n++; /* 孩子数加1 */
 if(n==i-1) /* 找到p的第i-1个孩子，其序号为k1 */
 break;
 l=k+1; /* c插在k+1处 */
 } /* p的序号为j，c插在l处 */
 if(l&lt;T-&gt;n) /* 插入点l不在最后 */
 for(k=T-&gt;n-1;k&gt;=l;k--) /* 依次将序号l以后的节点向后移c.n个位置 */
 T-&gt;nodes[k+c.n]=T-&gt;nodes[k];
 if(T-&gt;nodes[k].parent&gt;=l)
 T-&gt;nodes[k+c.n].parent+=c.n;
 for(k=0;k&lt;c.n;k++)
 T-&gt;nodes[l+k].data=c.nodes[k].data; /* 依次将树c的所有节点插于此处 */
 T-&gt;nodes[l+k].parent=c.nodes[k].parent+l;
 T-&gt;nodes[l].parent=j; /* 树c的根节点的父节点为p */
 T-&gt;n+=c.n; /* 树T的节点数加c.n个 */
 while(f)
 { /* 从插入点之后，将节点仍按层序排列 */
 f=0; /* 交换标志置0 */
 for(j=l;j&lt;T-&gt;n-1;j++)
 if(T-&gt;nodes[j].parent&gt;T-&gt;nodes[j+1].parent)
 {/* 如果节点j的父节点排在节点j+1的父节点之后（树没有按层序排列），交换两节点*/
 t=T-&gt;nodes[j];
 T-&gt;nodes[j]=T-&gt;nodes[j+1];
 T-&gt;nodes[j+1]=t;
 f=1; /* 交换标志置1 */
 for(k=j;k&lt;T-&gt;n;k++) /* 改变父节点序号 */
 if(T-&gt;nodes[k].parent==j)
 T-&gt;nodes[k].parent++; /* 父节点序号改为j+1 */
 else if(T-&gt;nodes[k].parent==j+1)
 T-&gt;nodes[k].parent--; /* 父节点序号改为j */
 return OK;
 else /* 树T不存在 */
 return ERROR;
删除子树.
Status deleted[MAX_TREE_SIZE+1]; /* 删除标志数组(全局量) */
void DeleteChild(PTree *T,TElemType p,int i)
 /* 操作结果：删除T中节点p的第i棵子树 */
 int j,k,n=0;
 LinkQueue q;
 QElemType pq,qq;
 for(j=0;j&lt;=T-&gt;n;j++)
 deleted[j]=0; /* 置初值为0(不删除标记) */
 pq.name='a'; /* 此成员不用 */
 InitQueue(&amp;q); /* 初始化队列 */
 for(j=0;j&lt;T-&gt;n;j++)
 if(T-&gt;nodes[j].data==p)
 break; /* j为节点p的序号 */
 for(k=j+1;k&lt;T-&gt;n;k++)
 if(T-&gt;nodes[k].parent==j)
 n++;
 if(n==i)
 break; /* k为p的第i棵子树节点的序号 */
 if(k&lt;T-&gt;n) /* p的第i棵子树节点存在 */
 n=0;
 pq.num=k;
 deleted[k]=1; /* 置删除标记 */
 n++;
 EnQueue(&amp;q,pq);
 while(!QueueEmpty(q))
 DeQueue(&amp;q,&amp;qq);
 for(j=qq.num+1;j&lt;T-&gt;n;j++)
 if(T-&gt;nodes[j].parent==qq.num)
 pq.num=j;
 deleted[j]=1; /* 置删除标记 */
 n++;
 EnQueue(&amp;q,pq);
 for(j=0;j&lt;T-&gt;n;j++)
 if(deleted[j]==1)
 for(k=j+1;k&lt;=T-&gt;n;k++)
 deleted[k-1]=deleted[k];
 T-&gt;nodes[k-1]=T-&gt;nodes[k];
 if(T-&gt;nodes[k].parent&gt;j)
 T-&gt;nodes[k-1].parent--;
 j--;
 T-&gt;n-=n; /* n为待删除节点数 */
层序遍历树.
void TraverseTree(PTree *T,void(*Visit)(TElemType))
 /* 操作结果：层序遍历树T,对每个节点调用函数Visit一次且仅一次 */
 int i;
 for(i=0;i&lt;T-&gt;n;i++)
 Visit(T-&gt;nodes[i].data);
 printf("\n");
孩子链表表示法.
存储结构.
/*树的孩子链表存储表示*/
typedef struct CTNode { // 孩子节点
 int child;
 struct CTNode *next;
} *ChildPtr;
typedef struct {
 ElemType data； // 节点的数据元素
 ChildPtr firstchild； // 孩子链表头指针
} CTBox;
typedef struct {
 CTBox nodes[MAX_TREE_SIZE]；
 int n, r； // 节点数和根节点的位置
} CTree;
森林、树与二叉树的转换.
见二叉树相应章节