后缀表达式求值:
后缀表达式是无需进行处理可以直接被计算机处理的表达式,运算符通常位于操作数的后面,例如: 3 4 + 5 * 6 - ,它是由中缀表达式(3 + 4) × 5 - 6转换过来的
后缀表达式进行求值时,设立一个栈s1,从左到右依次访问表达式中的元素,如果遇到数字直接压入栈中,如果遇到运算符就将栈中最上方的两个元素取出后进行相应的运算,将运算结果压入栈中。具体c++代码如下:
#include <iostream>
#include <stack>
#include <string>
using namespace std;
int main()
{
string s;
getline(cin,s); //这里需要注意,因为输入的后缀表达式操作数与运算符之间有空格隔开,因此不能用cin或者scanf进行读入
int len = s.size(); // cin或者scanf读入时,遇到空格就会判定为结束
int a,b;
stack<int> t;
int i;
for (i = 0;i < len;i++)
{
if (s[i] == '+' ||s[i] == '-' ||s[i] == '*' ||s[i] == '/' )
{
if (s[i] == '+')
{
a = t.top();
t.pop();
b = t.top();
t.pop();
a = a + b;
t.push(a);
}
else if (s[i] == '-')
{
a = t.top();
t.pop();
b = t.top();
t.pop();
a = b - a;
t.push(a);
}
else if (s[i] == '*')
{
a = t.top();
t.pop();
b = t.top();
t.pop();
a = a * b;
t.push(a);
}
else if (s[i] == '/')
{
a = t.top();
t.pop();
b = t.top();
t.pop();
a = b / a;
t.push(a);
}
i++;
}
else
{
int sum = 0;
while (s[i] != ' ')
{
sum *= 10;
sum += (s[i] - '0');
i++;
}
t.push(sum);
}
}
cout << t.top() << endl;
}
中缀表达式转换成后缀表达式
中缀表达式在求值时往往要先转换成相对应的后缀表达式,具体的做法是
1.设立两个栈t1,t2,分别用来存放运算符和操作数
2.从左至右扫描中缀表达式;
3.遇到操作数时,将其压入t2;
4.遇到运算符时,进行如下处理:
4-1.如果t1为空,或栈顶运算符为左括号“(”,或者该运算符为'(',则直接将此运算符入栈;
4-2.如果运算符为‘)’,那么依次将t1中的运算符弹出,压入t2,直到遇到一个‘(’,将它消除;
4-3.否则,将它与栈顶的运算符的优先级进行比较:
4-3-1.如果它的优先级大于栈顶运算符优先级,那么直接压入t1;
4-3-2.如果它的优先级小于栈顶运算符优先级,那么依次将t1中的运算符弹出,压入t2,直到遇见比它优先级小的,或者栈空,或者遇到‘(’,将它压入t1;
5.依次遍历完整个中缀表达式,栈t2中存放的就是所求的后缀表达式;
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
bool judge1(char s)
{
if (s == '+' || s == '-' || s == '*' || s == '/' || s == '(' || s == ')') return true;
else return false;
}
int getOp (char s)
{
if (s == '+') return 0;
else if (s == '-') return 1;
else if (s == '*') return 2;
else if (s == '/') return 3;
}
int op[4][4] = {0,0,0,0,
0,0,0,0,
1,1,0,0,
1,1,0,0};
bool judge2(char a,char b)
{
int op1 = getOp(a);
int op2 = getOp(b);
if (op[op1][op2] == 1) return true;
else return false;
}
int main()
{
char k;
vector<char> s;
while (scanf("%c",&k) != '\n') //这里其实有个很严重的错误,在读入中缀表达式的时候,操作数和运算符之间是有空格的,因此不能用cin或者是scanf
{
s.push_back(k); // 而必须使用getline()或者是gets() , 不过我懒得改了,具体可以参考上面的后缀表达式求值
}
int len = s.size();
stack<char> t1;
stack<char> t2;
for (int i = 0;i < len;i++)
{
bool temp1 = judge1(s[i]);
if (!temp1)
{
t2.push(s[i]);
}
else
{
if (s[i] == '(' || t1.empty() || t1.top() == '(')
{
t1.push(s[i]);
}
else if(s[i] == ')')
{
while (t1.top() != '(')
{
char ex = t1.top();
t2.push(ex);
t1.pop();
}
t1.pop();
}
else
{
bool temp2 = judge2(s[i],t1.top());
if (temp2)
{
t1.push(s[i]);
}
else
{
while (!t1.empty() && !judge2(s[i],t1.top()) && t1.top() != '(')
{
char tt = t1.top();
t2.push(tt);
t1.pop();
}
t1.push(s[i]);
}
}
}
}
while (!t1.empty())
{
char xx = t1.top();
t2.push(xx);
t1.pop();
}
stack<char> out;
while (!t2.empty())
{
char xx = t2.top();
out.push(xx);
t2.pop();
}
while (!out.empty())
{
cout << out.top();
out.pop();
}
cout << endl;
}
前缀表达式求值:
前缀表达式求值和后缀表达式求值方法很相似,只不过前缀表达式求值是从右往左扫描表达式,遇到操作数则压入栈中,遇到运算符则弹出两个操作数计算结果后重新压入
中缀表达式转前缀表达式:
与中缀转后缀相似,只说明一下不同点:
1.中缀转前缀是从右到左扫描
2.在中缀转后缀中,如果运算符比栈顶运算符的优先级高,则压入栈中,否则要依次弹出运算符栈中的元素,直到栈顶元素优先级比它低;而在中缀转前缀时,这一规则改变为如 果运算符比栈顶运算符的优先级高或它们的优先级相等,则压入栈中。