树-表达式树与prefix/infix/postfix的转换

本文详细介绍了如何通过前缀、中缀和后缀表达式构建表达式树,并提供了相应的算法实现。此外,还探讨了从表达式树导出前缀、中缀和后缀表达式的方法,以及它们之间的双射关系。这些内容对于理解计算表达式的内部工作原理和编译原理至关重要。
摘要由CSDN通过智能技术生成

众所周知
· 前缀/中缀/后缀表达式中的任意一个,都可以唯一确定一个表达式树;
· 对于表达式树进行前序/后序遍历可以得到前缀/后缀表达式,进行每次加括号的中序遍历可以得到中缀表达式。
· 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)//是否是运算数
根据中缀表达式转换表达式的算法,可以分为以下步骤: 1. 创建一个空栈和一个空的表达式。 2. 从左到右扫描中缀表达式中的每个元素。 3. 如果当前元素是操作数,则创建一个只包含该操作数的表达式,并将其压入栈中。 4. 如果当前元素是操作符,则创建一个只包含该操作符的表达式,并将其弹出栈两次,作为该操作符的左右子,然后将该表达式压入栈中。 5. 重复步骤2-4,直到扫描完整个中缀表达式。 6. 最后,栈中只剩下一个表达式,即为所求的表达式。 下面是一个Python实现的例子: ```python class TreeNode: def __init__(self, val): self.val = val self.left = None self.right = None def infix_to_expression_tree(infix): precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3} stack = [] for char in infix: if char.isalnum(): node = TreeNode(char) stack.append(node) elif char in precedence: node = TreeNode(char) while stack and stack[-1].val != '(' and precedence[char] <= precedence[stack[-1].val]: node.right = stack.pop() node.left = stack.pop() stack.append(node) stack.append(node) elif char == '(': stack.append(TreeNode(char)) elif char == ')': while stack and stack[-1].val != '(': node = stack.pop() if node.val in precedence: node.right = stack.pop() node.left = stack.pop() stack.append(node) stack.pop() while stack: node = stack.pop() if node.val in precedence: node.right = stack.pop() node.left = stack.pop() stack.append(node) return stack[0] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值