众所周知
· 前缀/中缀/后缀表达式中的任意一个,都可以唯一确定一个表达式树;
· 对于表达式树进行前序/后序遍历可以得到前缀/后缀表达式,进行每次加括号的中序遍历可以得到中缀表达式。
· prefix, infix, postfix, syntax tree四者两两均构成双射。
我们这里来讨论如何实现由三种表达式构造表达式树。
为了简便,我们只考虑中缀表达式带有全部括号的情况。(若完全不带有括号,则它根本不是中缀表达式,也不对应着唯一的表达式树。若只带有必要的括号,则可以先用其他方法将其变成带有全部括号的中缀表达式。)
1. 由prefix构建表达式树
BTREE GetSyntaxTree_Prefix(char prefix[])
{
char x = nextToken(prefix);
BTREE cur = (BTREE)malloc(sizeof(BTNode));
cur->data = x;
cur->lchild = cur->rchild = NULL;
if (!isOpNum(x)) { //若当前节点为操作数,则它必定没有子树
cur->lchild = GetSyntaxTree_Prefix(prefix);
cur->rchild = GetSyntaxTree_Prefix(prefix);
}
return cur;
}
2. 由带有全部括号的infix构建表达式树
注:如果prefix/postfix也带全部括号,则很容易由此法改造,得到 由带有全部括号的prefix/postfix构建表达式树 的函数
//每次进入这个递归,读取光标都将面对一个运算数/运算式,该函数应将它变成一个子树(之后会变为上一层的左/右子树)
BTREE GetSyntaxTree_Infix(char infix[])
{
char x = nextToken(infix);
BTREE cur = (BTREE)malloc(sizeof(BTNode));
cur->lchild = cur->rchild = NULL;
if (x == '(') { //遇左括号,说明面对的是运算式,需要建立子树
cur->lchild = GetSyntaxTree_Infix(infix);//构建左子树
cur->data = nextToken(infix);//此时一定读到操作符 赋给当前节点
cur->rchild = GetSyntaxTree_Infix(infix);//构建右子树
nextToken(infix);//此时一定读到右括号 吃掉它
}
else //否则,说明面对的是运算数,只需建立一个叶结点
cur->data = x;
return cur;
}
3. 由postfix构建表达式树
与1.相对称,这里需要从尾至头读取postfix序列。将字符串倒序是容易的。
BTREE GetSyntaxTree_Postfix(char postfix[])
{
char x = nextToken(postfix);
BTREE cur = (BTREE)malloc(sizeof(BTNode));
cur->data = x;
cur->lchild = cur->rchild = NULL;
if (!isOpNum(x)) { //若当前节点为操作数,则它必定没有子树
cur->rchild = GetSyntaxTree_Postfix(postfix);
cur->lchild = GetSyntaxTree_Postfix(postfix);
}
return cur;
}
4. 由表达式树得到prefix(前序遍历)
void GetPrefix(BTREE T)
{
if (T != NULL) {
printf("%c", T->data);
GetPrefix(T->lchild);
GetPrefix(T->rchild);
}
}
5. 由表达式树得到带全括号的infix(每次加括号的中序遍历)
如果去掉两个if判断,无脑输出左右括号,则单独的运算数也会自带括号。
void GetInfix(BTREE T)
{
if (T != NULL) {
if (T->lchild != NULL && T->rchild != NULL) { printf("("); }
GetInfix(T->lchild);
printf("%c", T->data);
GetInfix(T->rchild);
if (T->lchild != NULL && T->rchild != NULL) { printf(")"); }
}
}
6. 由表达式树得到postfix(后序遍历)
void GetPostfix(BTREE T)
{
if (T != NULL) {
GetPostfix(T->lchild);
GetPostfix(T->rchild);
printf("%c", T->data);
}
}
说明
typedef struct node
{
char data;
struct node * lchild;
struct node * rchild;
}BTNode, *BTREE;
char nextToken(char infix[])//得到fix的下一个字符
int isOpNum(char ch)//是否是运算数