题目描述
给定一串计算表达式
例如 (1+2*4-2)*3+4 * (2+4)/2
计算此表达式的值,并输出此表达式树的前序中序后序序列。
题解思路
首先,给定的表达式为正常逻辑的中缀表达式,我们需要将其转化为逆波兰式(后缀表达式),如下给出理由
例如 a*b-c
它的二叉树如下
前序序列为:- * a b c
中序序列为: a * b - c
后序序列为: a b * c -
对于前序序列,运算顺序应该为首先对离运算符最近的ab操作,ab前有乘号,将ab相乘,代替ab的位置,然后此时离运算符最近的为ab的结果与c,前方的操作符为-号则进行a*b-c操作。而此种运算顺序实际上不利于代码模拟。
相反,对于后序序列,则可以用栈轻松模拟,首先创建一个操作数栈,从左到右遍历。
- 首先为a,压入操作数栈
- 对b来说,压入操作数栈
- 对*来说,取出操作数栈中栈顶元素和次栈顶元素b,a并将这两个元素pop操作。将b,a进行相乘后重新压入操作数栈
- 对c来说,压入操作数栈
- 对-来说,取出操作数栈中栈顶元素和次栈顶c和a*b,将这两个元素进行先相减操作,重新压入栈。(注意为次栈顶减栈顶)
- 结束后栈中剩下的一个数则为表达式的值
因此我们想要计算表达式,可以先将其转化成逆波兰式(后缀表达式),就可以计算出值,而对于如何从中缀表达式转成后缀表达式,思路如下:
首先创建一个运算符栈,从左到右遍历,利用vector存储答案
- 如果为操作数,直接压入vector
- 如果为运算符
- 如果此时运算符栈为空,直接压入运算符栈
- 如果运算符为(,左括号的话,直接压入运算符栈
- 如果此时运算符为),右括号的话,不断将运算符栈顶元素压入vector,直到匹配到(,左括号为止(注意:左右括号都不进入vector)
- 如果此时运算符优先级大于栈顶元素,直接压入运算符栈
- 如果运算符优先级小于等于栈顶元素,不断将运算符栈顶元素压入vector,直到栈空或者栈顶元素优先级小于此运算符,然后将此运算符压入运算符栈。
vector中即为后缀表达式。
对于正确性,可以自己写几个例子简单模拟一下。
解决了从中缀转后缀,就可以算出值,而对于通过后缀表达式建立二叉树,思路与后缀表达式计算一样。
思路如下:(从左到右遍历后缀表达式)
首先创建一个指针栈
- 如果此时为操作数,创建指针指向此数,将指针压入栈
- 如果此时为操作符,创建指针指向此操作符,再将栈顶指针和次栈顶指针拿出,将此操作符指针的左孩子指针指向原次栈顶指针,右孩子指针指向原栈顶指针。再将此操作符指针压入栈中。
结束后栈中剩下的指针即为此二叉树的根结点指针。
代码如下
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <stack>
#include <vector>
using namespace std;
const int N=100010;
typedef struct node
{
char data[1000];
struct node *lchild;
struct node *rchild;
}node,*root;
string str,str1;
vector<string>res;
int ans=0;
int fun2(string a)//运算符优先级判断
{
if(a[0]=='+'||a[0]=='-')return 0;
if(a[0]=='*'||a[0]=='/')return 1;
if(a[0]=='(')return -1;
}
bool cmp(string a,string b)
{
int x=fun2(a),y=fun2(b);
if(x<y)return 1;
return 0;
}
void fun1()//中缀表达式转后缀表达式
{
vector<string>v;
string p="";
for(int i=0;i<str.size();i++)//对字符串切片处理
{
if(str[i]>='0'&&str[i]<='9')
{
p+=str[i];
}
else
{
if(p.size()!=0)v.push_back(p);
p=str[i];
v.push_back(p);
p="";
}
}
if(p.size())v.push_back(p);
stack<string>s;
for(int i=0;i<v.size();i++)
{
if(v[i][0]>='0'&&v[i][0]<='9')res.push_back(v[i]);
else
{
if(!s.size()||v[i][0]=='(')s.push(v[i]);
else
{
if(v[i][0]==')')
{
while(s.size())
{
string now=s.top();
s.pop();
if(now[0]=='(')break;
res.push_back(now);
}
}
else
{
if(cmp(s.top(),v[i]))s.push(v[i]);
else
{
while(s.size()&&!cmp(s.top(),v[i]))
{
res.push_back(s.top());
s.pop();
}
s.push(v[i]);
}
}
}
}
}
while(s.size())
{
res.push_back(s.top());
s.pop();
}
//for(int i=0;i<v.size();i++)cout<<v[i]<<endl;
}
root build()//二叉树建立
{
stack<root>s;
for(int i=0;i<res.size();i++)
{
node *no=(root)malloc(sizeof(node));
//cout<<"yes";
//cout<<res[i]<<endl;
if(res[i][0]>='0'&&res[i][0]<='9')
{
strcpy(no->data,res[i].c_str());
//cout<<no->data<<endl;
no->lchild=NULL;
no->rchild=NULL;
s.push(no);
}
else
{
strcpy(no->data,res[i].c_str());
no->rchild=s.top();
s.pop();
no->lchild=s.top();
s.pop();
s.push(no);
}
}
return s.top();
}
int js()//计算表达式的值
{
stack<int>s;
for(int i=0;i<res.size();i++)
{
if(res[i][0]>='0'&&res[i][0]<='9')
{
//cout<<"YES";
string temp=res[i];
//cout<<temp<<endl;
int tt=0;
for(int j=0;j<temp.size();j++)
{
tt=tt*10+temp[j]-'0';
}
s.push(tt);
//cout<<tt<<endl;
}
else
{
int a=s.top();
s.pop();
int b=s.top();
s.pop();
int temp=0;
if(res[i][0]=='+')temp=a+b;
else if(res[i][0]=='-')temp=b-a;
else if(res[i][0]=='*')temp=a*b;
else temp=b/a;
s.push(temp);
//cout<<temp<<endl;
}
}
return s.top();
}
void pre(root roo)//前序遍历
{
if(roo!=NULL)
{
cout<<roo->data;
pre(roo->lchild);
pre(roo->rchild);
}
}
void mid(root roo)//中序遍历
{
if(roo!=NULL)
{
mid(roo->lchild);
cout<<roo->data;
mid(roo->rchild);
}
}
void back(root roo)//后序遍历
{
if(roo!=NULL)
{
back(roo->lchild);
back(roo->rchild);
cout<<roo->data;
}
}
int main(void)
{
cin>>str;
fun1();
/* for(int i=0;i<res.size();i++)
{
cout<<res[i];
}
cout<<endl; */
root roo=build();//(1+2*4-2)*3+4*(2+4)/2
ans=js();
pre(roo);
cout<<endl;
mid(roo);
cout<<endl;
back(roo);
cout<<endl;
cout<<ans<<endl;
//system("pause");
return 0;
}