1、树的线性表示
树型结构和线性结构的主要区别在于树型结构具有分支性和层次性。使用树的遍历操作,可以将树中的结点按照规定的顺序排成一个线性序列;然而仅凭借树的某种遍历序列有时无法唯一地确定一棵树,但只要在遍历序列的基础上增加一些附加信息便可以唯一地确定一棵树,从而得到树的线性表示。树的线性表示便于树的输入、输出,同时在存储时也比较节省空间。
2、树的括号表示规则
(1)若树T为空树,则其括号表示为空
(2)若树T只包含一个结点,则其括号表示即为该结点本身
(3)若树T由根结点A和它的m棵子树T1,T2,...,Tm构成,则其括号表示为:A(T1的括号表示,T2的括号表示,... ,Tm的括号表示)
其中,子树的括号表示同样应该遵循以上规则
上图中树的括号表示为 A(B,C(F,G,H),D,E(I,J))
实现方法如下:
(1)从左到右扫描树的括号表示;
(2)每当遇到左括号时,其前一个结点进栈,并读入下一个符号;
(3)每当遇到右括号时,栈顶元素出栈。说明以栈顶元素为根的树(子树)构造完毕,此时若栈为空,算法结束,否则读入下一个符号
(4)每当遇到结点时,则它一定为栈顶元素的子女,将其挂到栈顶元素的某子女位置上,并读入下一个符号;
(5)每当遇到“,”,则略过该符号,并读入下一个符号。
通过一个例子说明具体实现代码如下:
设一棵完全二叉树为1(2(4(8,9),5(10,11)),3(6(12),7)) ,图形表示为
程序运行结果为:
实现代码:
//以括号表示法构建二叉树
void BrackToTree(char* line,BinaryTree* p)
{
int i=0;
int j=0;
//申请结点存储缓冲数组
char *buff = (char*)malloc((strlen(line)+1)*sizeof(char));
//定义并初始化栈
SqStack* pst = (SqStack*)malloc(sizeof(SqStack));
InitStack(pst);
BiTNode* pbt = NULL;//前一结点地址
while(ExtractNodeFromStr(line,&i,&j,buff))//遇到'\n'或'\0'时退出构建树
{
if(strcmp(buff,"(") == 0)
{
Push(pst,pbt);//前一结点入栈,作为子树根结点
}
else if(strcmp(buff,")") == 0)
{
Pop(pst);//栈顶元素出栈,表示一棵子树构建完毕
}
else if(strcmp(buff,",") == 0)
{
;//无作为
}
else//字符串
{
pbt = (BiTNode*)malloc(sizeof(BiTNode));//新建结点,更新前一结点
pbt->data = atoi(buff);//更新新建结点数据
pbt->lchild = NULL;
pbt->rchild = NULL;
if(StackEmpty(pst))//栈空
{
p->root = pbt;//直接作为树根结点
}
else
{
//printf("在父结点%d下,插入结点%d\n",(GetTop(pst))->data,pbt->data);
InsertChild(GetTop(pst),pbt);//将新建结点作为栈顶结点的子结点
}
}
}
//销毁栈
DestroyStack(pst);
//销毁缓冲数组
free(buff);
}