// c6-5.h 树的二叉链表(孩子—兄弟)存储结构(见图6.32)
typedef struct CSNode
{TElemType data;CSNode *firstchild,*nextsibling;
}CSNode,*CSTree;
一棵树无论有多少叉,它最多有一个长子和一个排序恰在其下的兄弟。根据这样的定
义,则每个结点的结构就都统一到了二叉链表结构上。这样有利于对结点进行操作。图
633 是图628(a)所示之树的二叉链表(孩子—兄弟)存储结构。
// func6-2.cpp bo6-5.cpp和algo7-1.cpp调用
void PreOrderTraverse(CSTree T,void(*Visit)(TElemType))
{ // 先根遍历孩子—兄弟二叉链表结构的树Tif(T){Visit(T->data); // 先访问根结点PreOrderTraverse(T->firstchild,Visit); // 再先根遍历长子子树PreOrderTraverse(T->nextsibling,Visit); // 最后先根遍历下一个兄弟子树}
}
// bo6-5.cpp 树的二叉链表(孩子—兄弟)存储(存储结构由c6-5.h定义)的基本操作(17个)
#define ClearTree DestroyTree // 二者操作相同
#include"func6-2.cpp" // 包括PreOrderTraverse()
void InitTree(CSTree &T)
{ // 操作结果:构造空树TT=NULL;
}
void DestroyTree(CSTree &T)
{ // 初始条件:树T存在。操作结果:销毁树Tif(T){if(T->firstchild) // T有长子DestroyTree(T->firstchild); // 销毁T的长子为根结点的子树if(T->nextsibling) // T有下一个兄弟DestroyTree(T->nextsibling); // 销毁T的下一个兄弟为根结点的子树free(T); // 释放根结点T=NULL;}
}
typedef CSTree QElemType; // 定义队列元素类型
#include"c3-2.h" // 定义LinkQueue类型(链队列)
#include"bo3-2.cpp" // LinkQueue类型的基本操作
void CreateTree(CSTree &T)
{ // 构造树Tchar c[20]; // 临时存放孩子结点(设不超过20个)的值CSTree p,p1;LinkQueue q;int i,l;InitQueue(q);printf("请输入根结点(字符型,空格为空): ");scanf("%c%*c",&c[0]);if(c[0]!=Nil) // 非空树{T=(CSTree)malloc(sizeof(CSNode)); // 建立根结点T->data=c[0];T->nextsibling=NULL;EnQueue(q,T); // 入队根结点的指针while(!QueueEmpty(q)) // 队不空{DeQueue(q,p); // 出队一个结点的指针printf("请按长幼顺序输入结点%c的所有孩子: ",p->data);gets(c);l=strlen(c);if(l>0) // 有孩子{p1=p->firstchild=(CSTree)malloc(sizeof(CSNode)); // 建立长子结点p1->data=c[0];for(i=1;i<l;i++){p1->nextsibling=(CSTree)malloc(sizeof(CSNode)); // 建立下一个兄弟结点EnQueue(q,p1); // 入队上一个结点p1=p1->nextsibling;p1->data=c[i];}p1->nextsibling=NULL;EnQueue(q,p1); // 入队最后一个结点}elsep->firstchild=NULL; // 长子指针为空}}elseT=NULL; // 空树
}
Status TreeEmpty(CSTree T)
{ // 初始条件:树T存在。操作结果:若T为空树,则返回TURE;否则返回FALSEif(T) // T不空return FALSE;elsereturn TRUE;
}
int TreeDepth(CSTree T)
{ // 初始条件:树T存在。操作结果:返回T的深度CSTree p;int depth,max=0;if(!T) // 树空return 0;if(!T->firstchild) // 树无长子return 1;for(p=T->firstchild;p;p=p->nextsibling){ // 求子树深度的最大值depth=TreeDepth(p);if(depth>max)max=depth;}return max+1; // 树的深度=子树深度最大值+1
}
TElemType Value(CSTree p)
{ // 返回p所指结点的值return p->data;
}
TElemType Root(CSTree T)
{ // 初始条件:树T存在。操作结果:返回T的根if(T)return Value(T);elsereturn Nil;
}
CSTree Point(CSTree T,TElemType s)
{ // 返回二叉链表(孩子—兄弟)树T中指向元素值为s的结点的指针。另加LinkQueue q;QElemType a;if(T) // 非空树{InitQueue(q); // 初始化队列EnQueue(q,T); // 根结点入队while(!QueueEmpty(q)) // 队不空{DeQueue(q,a); // 出队,队列元素赋给aif(a->data==s)return a;if(a->firstchild) // 有长子EnQueue(q,a->firstchild); // 入队长子if(a->nextsibling) // 有下一个兄弟EnQueue(q,a->nextsibling); // 入队下一个兄弟}}return NULL;
}
Status Assign(CSTree &T,TElemType cur_e,TElemType value)
{ // 初始条件:树T存在,cur_e是树T中结点的值。操作结果:改cur_e为valueCSTree p;if(T) // 非空树{p=Point(T,cur_e); // p为cur_e的指针if(p) // 找到cur_e{p->data=value; // 赋新值return OK;}}return ERROR ; // 树空或没找到
}
TElemType Parent(CSTree T,TElemType cur_e)
{ // 初始条件:树T存在,cur_e是T中某个结点// 操作结果:若cur_e是T的非根结点,则返回它的双亲;否则函数值为“空”CSTree p,t;LinkQueue q;InitQueue(q);if(T) // 树非空{if(Value(T)==cur_e) // 根结点值为cur_ereturn Nil;EnQueue(q,T); // 根结点入队while(!QueueEmpty(q)){DeQueue(q,p);if(p->firstchild) // p有长子{if(p->firstchild->data==cur_e) // 长子为cur_ereturn Value(p); // 返回双亲t=p; // 双亲指针赋给tp=p->firstchild; // p指向长子EnQueue(q,p); // 入队长子while(p->nextsibling) // 有下一个兄弟{p=p->nextsibling; // p指向下一个兄弟if(Value(p)==cur_e) // 下一个兄弟为cur_ereturn Value(t); // 返回双亲EnQueue(q,p); // 入队下一个兄弟}}}}return Nil; // 树空或没找到cur_e
}
TElemType LeftChild(CSTree T,TElemType cur_e)
{ // 初始条件:树T存在,cur_e是T中某个结点// 操作结果:若cur_e是T的非叶子结点,则返回它的最左孩子;否则返回“空”CSTree f;f=Point(T,cur_e); // f指向结点cur_eif(f&&f->firstchild) // 找到结点cur_e且结点cur_e有长子return f->firstchild->data;elsereturn Nil;
}
TElemType RightSibling(CSTree T,TElemType cur_e)
{ // 初始条件:树T存在,cur_e是T中某个结点// 操作结果:若cur_e有右兄弟,则返回它的右兄弟;否则返回“空”CSTree f;f=Point(T,cur_e); // f指向结点cur_eif(f&&f->nextsibling) // 找到结点cur_e且结点cur_e有右兄弟return f->nextsibling->data;elsereturn Nil; // 树空
}
Status InsertChild(CSTree &T,CSTree p,int i,CSTree c)
{ // 初始条件:树T存在,p指向T中某个结点,1≤i≤p所指结点的度+1,非空树c与T不相交// 操作结果:插入c为T中p结点的第i棵子树// 因为p所指结点的地址不会改变,故p不需是引用类型int j;if(T) // T不空{if(i==1) // 插入c为p的长子{c->nextsibling=p->firstchild; // p的原长子现是c的下一个兄弟(c本无兄弟)p->firstchild=c;}else // 找插入点{p=p->firstchild; // 指向p的长子j=2;while(p&&j<i){p=p->nextsibling;j++;}if(j==i) // 找到插入位置{c->nextsibling=p->nextsibling;p->nextsibling=c;}else // p原有孩子数小于i-1return ERROR;}return OK;}else // T空return ERROR;
}
Status DeleteChild(CSTree &T,CSTree p,int i)
{ // 初始条件:树T存在,p指向T中某个结点,1≤i≤p所指结点的度// 操作结果:删除T中p所指结点的第i棵子树// 因为p所指结点的地址不会改变,故p不需是引用类型CSTree b;int j;if(T) // T不空{if(i==1) // 删除长子{b=p->firstchild;p->firstchild=b->nextsibling; // p的原次子现是长子b->nextsibling=NULL;DestroyTree(b);}else // 删除非长子{p=p->firstchild; // p指向长子j=2;while(p&&j<i){p=p->nextsibling;j++;}if(j==i) // 找到第i棵子树{b=p->nextsibling;p->nextsibling=b->nextsibling;b->nextsibling=NULL;DestroyTree(b);}else // p原有孩子数小于ireturn ERROR;}return OK;}elsereturn ERROR;
}
void PostOrderTraverse(CSTree T,void(*Visit)(TElemType))
{ // 后根遍历孩子—兄弟二叉链表结构的树TCSTree p;if(T){if(T->firstchild) // 有长子{PostOrderTraverse(T->firstchild,Visit); // 后根遍历长子子树p=T->firstchild->nextsibling; // p指向长子的下一个兄弟while(p){PostOrderTraverse(p,Visit); // 后根遍历下一个兄弟子树p=p->nextsibling; // p指向再下一个兄弟}}Visit(Value(T)); // 最后访问根结点}
}
void LevelOrderTraverse(CSTree T,void(*Visit)(TElemType))
{ // 层序遍历孩子—兄弟二叉链表结构的树TCSTree p;LinkQueue q;InitQueue(q);if(T){Visit(Value(T)); // 先访问根结点EnQueue(q,T); // 入队根结点的指针while(!QueueEmpty(q)) // 队不空{DeQueue(q,p); // 出队一个结点的指针if(p->firstchild) // 有长子{p=p->firstchild;Visit(Value(p)); // 访问长子结点EnQueue(q,p); // 入队长子结点的指针while(p->nextsibling) // 有下一个兄弟{p=p->nextsibling;Visit(Value(p)); // 访问下一个兄弟EnQueue(q,p); // 入队兄弟结点的指针}}}}
}
// main6-5.cpp 检验bo6-5.cpp的主程序
#include"c1.h"
typedef char TElemType;
TElemType Nil=' '; // 以空格符为空
#include"c6-5.h"
#include"bo6-5.cpp"
void vi(TElemType c)
{printf("%c ",c);
}
void main()
{int i;CSTree T,p,q;TElemType e,e1;InitTree(T);printf("构造空树后,树空否? %d(1:是0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T));CreateTree(T);printf("构造树T后,树空否? %d(1:是0:否) 树根为%c 树的深度为%d\n",TreeEmpty(T),Root(T),TreeDepth(T));printf("先根遍历树T:\n");PreOrderTraverse(T,vi);printf("\n请输入待修改的结点的值新值: ");scanf("%c%*c%c%*c",&e,&e1);Assign(T,e,e1);printf("后根遍历修改后的树T:\n");PostOrderTraverse(T,vi);printf("\n%c的双亲是%c,长子是%c,下一个兄弟是%c\n",e1,Parent(T,e1),LeftChild(T,e1),RightSibling(T,e1));printf("建立树p:\n");InitTree(p);CreateTree(p);printf("层序遍历树p:\n");LevelOrderTraverse(p,vi);printf("\n将树p插到树T中,请输入T中p的双亲结点子树序号: ");scanf("%c%d%*c",&e,&i);q=Point(T,e);InsertChild(T,q,i,p);printf("层序遍历树T:\n");LevelOrderTraverse(T,vi);printf("\n删除树T中结点e的第i棵子树,请输入e i: ");scanf("%c%d",&e,&i);q=Point(T,e);DeleteChild(T,q,i);printf("层序遍历树T:\n",e,i);LevelOrderTraverse(T,vi);printf("\n");DestroyTree(T);
}
代码的运行结果:
构造空树后,树空否? 1(1:是0:否) 树根为树的深度为0
请输入根结点(字符型,空格为空): R
请按长幼顺序输入结点R的所有孩子: ABC
请按长幼顺序输入结点A的所有孩子: DE
请按长幼顺序输入结点B的所有孩子:
请按长幼顺序输入结点C的所有孩子: F
请按长幼顺序输入结点D的所有孩子:
请按长幼顺序输入结点E的所有孩子:
请按长幼顺序输入结点F的所有孩子: GHK
请按长幼顺序输入结点G的所有孩子:
请按长幼顺序输入结点H的所有孩子:
请按长幼顺序输入结点K的所有孩子:
构造树T后,树空否? 0(1:是0:否) 树根为R 树的深度为4
先根遍历树T:(见图628(a))
R A D E B C F G H K
请输入待修改的结点的值新值: D d
后根遍历修改后的树T:
d E A B G H K F C R
d的双亲是A,长子是,下一个兄弟是E
建立树p:
请输入根结点(字符型,空格为空): f
请按长幼顺序输入结点f的所有孩子: ghk
请按长幼顺序输入结点g的所有孩子:
请按长幼顺序输入结点h的所有孩子:
请按长幼顺序输入结点k的所有孩子:
层序遍历树p:(见图629)
f g h k
将树p插到树T中,请输入T中p的双亲结点子树序号: R 3
层序遍历树T:(见图630)
R A B f C d E g h k F G H K
删除树T中结点e的第i棵子树,请输入e i: C 1
层序遍历树T:(见图631)
R A B f C d E g h k