数据结构 | 中缀表达式,前缀表达式,后缀表达式,创建语法树,计算结果

目录

         语法树
         中缀表达式
         前缀表达式
         后缀表达式
         根据中缀表达式创建语法树
         根据前缀表达式创建二叉树
         根据后缀表达式计算结果

语法树

语法树即将运算符作为根节点,将数字作为左右节点。

下面以中缀表达式A+B*(C-D)+E/F为例画出一颗语法树,步骤:
(1)从当前的中缀表达式中选择最后执行的四则运算符,作为当前的根节点,若没有运算符,将数字写在对应的节点处;
(2) 该运算符将中缀表达式分为左右两部分,即为左右子树,重复步骤(1);
中缀表达式语法树

中缀表达式

中缀表达式是一个通用的算术或逻辑公式表示方法。 中缀表达式就是我们通常理解的表达式,如13+5*(2-0)。中序遍历语法树即可得到中缀表达式。

前缀表达式(波兰式)

前缀表达式是一种没有括号的算术表达式,与中缀表达式不同的是,其将运算符写在前面,操作数写在后面。 先序遍历语法树可得到前缀表达式,上图的前缀表达式为:++A*B-CD/EF。

后缀表达式(逆波兰式)

后缀表达式即将运算符写在操作数之后 后序遍历语法树可得到后缀表达式,上图的后缀表达式为:ABCD-*+EF/+。

根据中缀表达式创建二叉树,并通过层次遍历验证树的结构

思路:
(1)遍历字符数组,若为数字则创建节点并存入节点栈;
(2)若为运算符,当运算符栈为空则直接入栈;
(3)若为运算符,当运算符不为空且运算符优先级比运算符栈顶元素低时,将运算符存入运算符栈并为数组下一位创建节点存入节点栈;当运算符栈不为空时,循环取出栈顶元素创建节点并连接节点栈中元素(先连接右节点再连接左节点);
(4)判断运算符栈是否为空,若不为空,则取出栈顶元素为其创建节点并连接节点栈中元素。

struct tree
{
	char c;
	struct tree* left;
	struct tree* right;
};
stack<struct tree*> subTreeStack; //节点栈 
stack<char> operatorStack; //运算符栈 
 
struct tree* BuildTree(char str[])
{
	struct tree* node;
	for (unsigned int pos = 0; pos < strlen(str); pos++)
	{
		if (str[pos] - '0' >= 0 && str[pos] - '0' <= 9)    //若是数字则作为叶子节点  
		{
 
			node = (struct tree*) malloc(sizeof(struct tree));
			node->c = str[pos];
			node->left = NULL;
			node->right = NULL;
 
			subTreeStack.push(node);
		}
		else if (str[pos] == '*' || str[pos] == '/' || str[pos] == '+' || str[pos] == '-')
		{
			if (!operatorStack.empty() && (str[pos] == '+' || str[pos] == '-'))  //若优先级比栈顶元素低  
			{
				operatorStack.push(str[pos]);
				
				node = (struct tree*) malloc(sizeof(struct tree));
				node->c = str[pos+1];
				node->left = NULL;
				node->right = NULL;
				
 				subTreeStack.push(node);
 				
				while(!operatorStack.empty()){
					node = (struct tree*) malloc(sizeof(struct tree));
					node->c = operatorStack.top();
					node->right = subTreeStack.top();
					subTreeStack.pop();
					node->left = subTreeStack.top();
					subTreeStack.pop();
					
					subTreeStack.push(node);
					
					operatorStack.pop();
				}
				pos++;
			}
			else
				operatorStack.push(str[pos]);
		} 
 
	}
 
	while (!operatorStack.empty())
	{
 
		node = (struct tree*) malloc(sizeof(struct tree));
		node->c = operatorStack.top();
		operatorStack.pop();
		node->right = subTreeStack.top();
		subTreeStack.pop();
		node->left = subTreeStack.top();
		subTreeStack.pop();
 
		subTreeStack.push(node);
 
	}
	return subTreeStack.top();
}

int BiTree_height(struct tree* root)//求树的深度算法
{
	if(root==NULL)
		return 0;
	else
	{
		if(BiTree_height(root->left)>BiTree_height(root->right))
				return 1+BiTree_height(root->left);
		else
				return 1+BiTree_height(root->right);
	
	}
} 

void printNodeAtLevel(struct tree* root,int level)  
{  
    if(root==NULL||level<0)  
        return;  
  
    if(level==0)  
    {  
    printf("%c ",root->c);
	return;  
    }  
  
    // 左子树的 level - 1 级  
    printNodeAtLevel(root->left,level-1);  
  
    // 右子树的 level - 1 级  
    printNodeAtLevel(root->right,level-1);  
}

//将树按层次遍历 
void levelOrder(struct tree* root)
{
	if(root==NULL)
		return;
	int totalLevel = BiTree_height(root);
	for(int i = 0; i< totalLevel; i++)
	{
		printNodeAtLevel(root, i);
		cout<<endl;//打印完一层,换行
	}
} 

根据前缀表达式递归创建二叉树

即根据先序遍历序列递归创建二叉树,当结点没有左右孩子时用‘#’表示为空,上图语法树结构如下图所示:
“#”表示为空
实现代码如下:

typedef struct BiTNode
{
    char data;
    struct BiTNode *lchild, *rchild;;
}BiTNode, *BiTree;

int CreateBiTree(BiTree &T)
{
    //按先序次序输入二叉树中的结点的值(一个字符), #表示空树
    //构造二叉链表表示的二叉树T
	char a;
	scanf("%c",&a);
	if(a == '#')
		T = NULL;
	else{
		T=(BiTNode *)malloc(sizeof(BiTNode));
		T->data = a;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
	return 1;

}

根据后缀表达式计算结果

思路:
(1)将后缀表达式存入字符数组中,定义数字数组用于存操作数,并且定义top变量充当指针功能;
(2)遍历字符数组,倘若为操作数则直接存入数字数组中,top++;
(3)倘若为运算符,则从数字数组中取出两个数进行四则运算。注意:先取出右操作数,后取出左操作数。
(4)将计算结果重新写入数字数组中覆盖原先操作数;
(5)循环以上操作,直到遍历结束。

//基本四则运算
int cal(char op,int a,int b)
{
	if(op == '+')
		return a + b;
	if(op == '-')
		return a - b;
	if(op == '*')
		return a * b;
	if(op == '/'){
		if(b == 0){
			cout<<"Error!"<<endl;
			return 0;
		}
		else{
			return a / b;
		}
	}
	return 1;
}

//逆波兰表达式求结果
int ReversePolishCal(char exp[])
{
	int len = strlen(exp);
	int stack[100], top=-1;
	int a, b, c;
	char op;
	
	for(int i=0;i<len;i++){
		if(exp[i] - '0' >=  0 && exp[i] - '0' <= 9){
			stack[++top] = exp[i] - '0';
		}
		else{
			op = exp[i];
			b = stack[top--];
			a = stack[top--];
			c = cal(op, a, b);
			stack[++top] = c;
		}
	}
	return stack[top];	
}
  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值