中缀表达式转换成后缀表达式
题目:所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右进行
例1:中缀表达式: 3*(5–2)+7 对应的后缀表达式为:352-*7+
例2:中缀表达式: 2+48+(88+1)/3 对应的后缀表达式为 248+881+3/+
考察内容:栈的基本使用
以下解题默认输入的中缀表达式是正确的,即都有解(不考虑分母是0的情况等)。
第一版源代码:
#include<iostream>
#include<vector>
#include<stack>
#include<string>
using namespace std;
int value(char c)
{
switch(c)//优先级:乘除>加减>左括号
{
case'(':return 1;break;
case'+':
case'-':return 2;break;
case'*':
case'/':return 3;break;
}
}
string change(string a)
{
string str;
stack<char>data;
int len=a.length();
for(int i=0;i<len;i++)
{
//(1) 如果遇到数字,直接放到后缀表达式尾
if(a[i]>='1'&&a[i]<='9')
{
str+=a[i];
}
//(2) 如果遇到遇到运算符
else
{
if(a[i]=='(')//a.若当前运算符为'('直接入栈
{
data.push(a[i]);
}
else if(a[i]==')')//b.若当前运算符为’)’则将栈顶元素出栈置于后缀表达式尾, 直到遇到运算符’(‘, 注意’(’ 与 ‘)’不用置于后缀表达式尾
{
while(data.top()!='(')
{
str+=data.top();
data.pop();
}
data.pop();
}
else if(data.empty())//c.若此时栈空,则直接入栈
{
data.push(a[i]);
}
else
{
if(value(a[i])>value(data.top()))data.push(a[i]);//d.若栈stack不空且当前运算符优先级大于栈顶运算符优先级,则将此运算符直接入栈
else
{
while(value(a[i])<=value(data.top()))//e,循环:若栈stack不空且当前运算符优先级小于或等于栈顶运算符的优先级,则将栈顶运算符依次出栈,置于后缀表达式尾
{
str+=data.top();
data.pop();
if(data.empty())break;
}
data.push(a[i]);
}
}
}
}
//(3)若此时栈stack不为空, 则将栈顶运算符依次出栈置于后缀表达式尾.
if(!data.empty())
{
while(!data.empty())
{
str+=data.top();
data.pop();
}
}
return str;
}
int main()
{
string a;
cin>>a;
cout<<"中缀表达式:"<<a<<endl;
string b=change(a);
cout<<"后缀表达式:"<<b<<endl;
return 0;
}
运行结果:
代码缺陷:
- 这样的后缀表达式似乎无法求值,那不就失去意义了?或许需要把两个数用空格分开?
- 没考虑负数的情况,负号和减号似乎有点难区分?运算符后又跟着一个‘-’,这是负号?
针对以上问题,本小白又做了些改进~(顺便也把求值结果也给求了)
第二版源代码:
#include<iostream>
#include<vector>
#include<stack>
#include<string>
using namespace std;
int value(char c)
{
switch(c)//优先级:乘除>加减>左括号
{
case'(':return 0;break;
case'+':
case'-':return 1;break;
case'*':
case'/':return 2;break;
}
}
string change(string a)
{
string str;
stack<char>data;
int ret=1;//用来判断'-'是减号还是负号 ,这里设置1是负号,0是减号
int len=a.length();
for(int i=0;i<len;i++)
{
//(1) 如果遇到数字,直接放到后缀表达式尾
if(a[i]>='0'&&a[i]<='9')
{
str+=a[i];
ret=0;//接在数字后面的'-'只能是减号
if(a[i+1]=='+'||a[i+1]=='-'||a[i+1]=='*'||a[i+1]=='/'||a[i+1]=='('||a[i+1]==')')str+=' ';
}
//(2) 如果遇到遇到符号
else
{
if(a[i]=='(')//a.若当前运算符为'('直接入栈
{
data.push(a[i]);
}
else if(a[i]==')')//b.若当前运算符为’)’则将栈顶元素出栈置于后缀表达式尾, 直到遇到运算符’(‘, 注意’(’ 与 ‘)’不用置于后缀表达式尾
{
while(data.top()!='(')
{
str+=' ';
str+=data.top();
str+=' ';
data.pop();
}
data.pop();
}
else//如果遇到运算符
{
if(ret)
{
data.push(a[i]);
ret=0;
}
else
{
if(data.empty())data.push(a[i]);//c.若此时栈空,则直接入栈
else
{
if(value(a[i])>value(data.top()))data.push(a[i]);//d.若栈stack不空且当前运算符优先级大于栈顶运算符优先级,则将此运算符直接入栈
else
{
while(value(a[i])<=value(data.top()))//e,循环:若栈stack不空且当前运算符优先级小于或等于栈顶运算符的优先级,则将栈顶运算符依次出栈,置于后缀表达式尾
{
str+=' ';
str+=data.top();
str+=' ';
data.pop();
if(data.empty())break;
}
data.push(a[i]);
}
}
ret=1;
}
}
}
}
//(3)若此时栈stack不为空, 则将栈顶运算符依次出栈置于后缀表达式尾.
if(!data.empty())
{
while(!data.empty())
{
str+=' ';
str+=data.top();
str+=' ';
data.pop();
}
}
return str;
}
long long int calculate(string str)
{
stack<long long int>data;
long long int c1,c2;
int n=str.length();
long long int num=0;//num用来记录每个数字的大小
int ret=0,fu_ret=0;//ret用来记录数字是否存在 ,fu_ret用来记录数字是否为负数
for(int i=0;i<n;i++)
{
if(str[i]==' ')
{
if(ret)
{
if(fu_ret)
{
data.push((-1)*num);
num=0;
ret=0;
fu_ret=0;
}
else
{
data.push(num);
num=0;
ret=0;
}
}
}
else if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/')
{
if(str[i]=='-'&&str[i+1]>='0'&&str[i+1]<='9')fu_ret=1;
else
{
c1=data.top();
data.pop();
c2=data.top();
data.pop();
if(str[i]=='+')data.push(c2+c1);
if(str[i]=='-')data.push(c2-c1);
if(str[i]=='*')data.push(c2*c1);
if(str[i]=='/')data.push(c2/c1);
}
}
else
{
num=num*10+str[i]-'0';
ret=1;
}
}
return data.top();
}
int main()
{
string a;
cin>>a;
cout<<"中缀表达式:"<<a<<endl;
string b=change(a);
cout<<"后缀表达式:";
int n=b.length();
for(int i=0;i<n;i++)
{
if(b[i]!=' ')cout<<b[i];
}
cout<<endl;
cout<<"result:"<<calculate(b)<<endl;
return 0;
}
运行结果:
其实还并不清楚这种方法是如何想出的,只知道有这样一种解决四则运算问题的方法,还有待我继续思考呀
不过,参考了各方的材料,进行了总结,最后还是写完了代码~~(挺开心)
Emma,总觉得还有哪些bug?欢迎大家指出