括号法表示二叉树,如下例:
A(B(#,D),C(E(#,F),#))
字母代表结点,字母后面的括号为该结点的子树,逗号左边为左子树,逗号右边为右子树。
建立:
观察括号法的表达式可知,处理完一个结点后,紧接着是继续处理其子结点,处理完其子结点,又要继续处理其子结点的子结点,即后来的先处理,是一种后进先出的思想,所以这里将借助栈结构完成此算法。
观察括号法的表达式易知,输入的字符有以下几类:①正常字符(如字母):用户要保存到结点中的值;②左括号:其右边跟着的是其左边那个结点的子树;③逗号:其右边是其左边那个结点的兄弟结点;④右括号:表示左边那个结点不再有子树,且其父结点也不再有子树;⑤井号:表示无效字符,将指针值设为nullptr。
首先获取栈顶结点,然后获取输入的字符,不同的字符做不同的处理。如果是左括号,代表当前结点有左子树,则左子树申请一块内存,并将左子树地址压入栈中;如果是逗号,说明当前结点有右子树,则申请内存并压入栈;如果是右括号,说明当前结点处理完毕,将其及其右子树都弹出栈;如果是井号,则删除当前结点并出栈,此时的新栈顶便是其父结点,要将父结点的左子树或右子树设置为nullptr;如果是正常字符,保存到当前结点中即可。重复这个过程,直到栈空。
void BracketsCreatBiTree(BiTree *&T)
{
stack<BiTree*> S;
//先处理根结点
char ch;
cin >> ch;
if (ch == '#')
{
T = nullptr;
return;
}
T = new BiTree;
T->data = ch;
S.push(T);
BiTree *p=T;
//循环处理子树
while (!S.empty())
{
p = S.top();
cin >> ch;
if (ch == '(')//表示当前结点拥有子树
{
p->lchild = new BiTree;
S.push(p->lchild);
}
else if (ch == ',')//表示当前结点拥有右子树
{
p->rchild = new BiTree;
S.push(p->rchild);
}
else if (ch == ')')//表示一个结点的左右子树处理完毕,将其及其右子树出栈
{
S.pop();
S.pop();
}
else if (ch == '#')//表示当前结点为空
{
delete p;
S.pop();
p = S.top();
if (p->rchild == nullptr) p->lchild = nullptr;
else p->rchild = nullptr;
}
else//表示当前获取到的字符为要保存的值
{
p->data = ch;
}
}
}
遍历:
先输出根结点,若不存在就输出“#”;
如果有子树存在,先输出左括号,然后判断左子树是否存在,存在则递归,不存在则输出“#”;
再输出逗号,如果右子树存在,递归右子树,否则输出“#”,最后输出右括号。
void BracketsTravers(BiTree *&T)
{
cout << T->data;
if(T->lchild!=nullptr || T->rchild!=nullptr)//若存在子树
{
cout << "(";
if(T->lchild!=nullptr) BracketsTravers(T->lchild);//若存在左子树
else cout << "#";
cout << ",";
if(T->rchild!=nullptr) BracketsTravers(T->rchild);//若存在右子树
else cout << "#";
cout << ")";
}
}