P21笔记,视频地址👇
http://www.bilibili.com/video/BV1Fv4y1f7T1?p=21&vd_source=02dfd57080e8f31bc9c4a323c13dd49c
思路
在上次我们其实已经了解了转换和计算过程,我们知道怎么转换,现在就是要把转换的这个过程用代码来呈现。
梳理一下思路吧。也就是输入一个中缀表达式的字符串,将其转化为后缀表达式的字符串。
当我们从左到右看的时候(遍历),遇到数字是直接添加到字符串里,这是没什么疑问的。
每遇到一个操作符就入栈,因为当我们读取到这个操作符的时候,并不知道其后的操作数是一个数还是一个表达式,需要继续向后读取才能确定。
倘若栈中不为空栈顶不为括号 且 当前操作符比栈顶的操作符优先级高,那么就可以将该操作符直接加到字符串末尾,其余请况下都是直接将操作符入栈。因为当栈顶是括号的时候,说明这是一个独立的新的表达式,所遇到的操作符应该入栈的,因为我们不知道该操作符下一位操作数是什么。
当遇到括号的时候,说明我们就要先只管计算括号内的内容,括号外的内容与其无关,把括号内的内容独立出来当作新的表达式进行操作。
如果遇到左括号也是直接添加到字符串末尾,因为这表示着括号后面的是一个独立的表达式,单独计算。如果遇到的是右括号,那么在栈不为空 且 未读取到栈上与其匹配的左括号之前,都不断将栈上的操作符按顺序出栈(因为根据我们的存放规则,存放进去的操作符从下到上优先级是不断提高的)
当遍历完整个中缀字符串的时候,栈中如果还有操作符就直接全部弹出即可。
主要函数
在遍历字符串会出现的几种情况中,操作数就不用说了,没有其他的情况,不需要特别的判断(我这里仍然适用于多位数,实现条件之前的文章里说过)。接着是操作符,由于我们的符号里会有运算符和括号,所以我单独封装了一个判断操作符函数,也比较简单。
在判断操作符是否入栈时,我们需要一个判断操作符优先级的函数。
在判断谁优先级高之前,要先规定优先级次序,适合单独写一个函数。该函数的参数应该是一个操作符,返回值应该是一个权重,可以理解哈。'+' '-' 的优先级其实是一样的,权重设为1,'*' ' /' 同理其权重设为2,可以使用switch函数,注意在每个情况之后要加break。
在判断操作符优先级的函数中调用优先级次序的函数之后才能进行比较。用三目运算符的式子来作为return的值比较方便直接。
还有一个判断栈顶元素是否是括号的函数。也比较直白。
感觉很乱,,,这么多函数,当然有的可能不封函数也行。
在写的时候我发现可以不用引strlen计算字符串长度的头文件,因为c++的string类型数据本身就带着很多的封装函数。下图取自bing
我写的时候入栈是用了上图的函数,但其实在字符串末尾加上字符是可以直接+=什么的,更简洁一点。
!!注意
1.函数比较多,注意其参数类型和返回类型。
2.在输入的时候,注意格式一定要正确。每个独立的符号之间都用 ' ' 隔开,否则程序会执行错误!!(咳咳我错了好几次....
3.switch函数每个case之后记得加break
代码如下
// 中缀表达式 转 后缀表达式
#include <iostream>
#include <stack>
using namespace std;
// 判断括号
bool Bracket(char a)
{
if (a == '(' || a == '{' || a == '[' || a == ')' || a == '}' || a == ']')
return 0;
return 1;
}
// 判断操作符优先级
int GetOperatorWeight(char op)
{
int weight = -1;
switch (op)
{
case '+':
case '-':
weight = 1;
break;
case '*':
case '/':
weight = 2;
break;
}
return weight;
}
int HasHigher(char op1, char op2)
{
/*if (op1 == '(' || op1 == '[' || op1 == '{')
return false;这里因为前提已经确定了该符号不是括号,所以不需要判断这一步*/
int op1Weight = GetOperatorWeight(op1);
int op2Weight = GetOperatorWeight(op2);
return op1Weight > op2Weight ? true : false;
}
// 判断是否是操作符
bool Isoperator(char C)
{
if (C == '+' || C == '-' || C == '*' || C == '/')
return 1;
return 0;
}
string exchange(string A)
{
stack<char> S;
string postfix = "";//初始化字符串为空
for (int i = 0; i < A.size(); i++)
{
if (A[i] == ' ')
continue;
else if (A[i] >= 48 && A[i] <= 57) // 操作数
{
while (A[i] != ' ' && i < A.size())
{
postfix.push_back(A[i++]);
}
postfix.push_back(' '); // 添加空格以区分操作数
}
else if (Isoperator(A[i])) // 操作符
{
while (!S.empty() && HasHigher(S.top(), A[i]) && Bracket(S.top()))
{
//出栈入字符串
postfix.push_back(S.top());
S.pop();
}
S.push(A[i]);//入栈
}
else if (A[i] == '(' || A[i] == '{' || A[i] == '[') // 括号
{
S.push(A[i]);
}
else if (A[i] == ')' || A[i] == '}' || A[i] == ']')
{ // 右括号:左括号之前的操作符均出栈之后,弹出左括号
while (!S.empty() && S.top() != '(' && S.top() != '{' && S.top() != '[')
{
postfix.push_back(S.top());
S.pop();
}
S.pop();
}
}
// 遍历完字符串中元素之后,弹出栈中剩余元操作符
while (!S.empty())
{
postfix += S.top();//这样的写法比较简洁
S.pop();
}
return postfix;
}
int main()
{
string A;
cout << "Enter Infix Expression \n";
getline(cin, A);
string postfix = exchange(A);
cout << "Output = " << postfix << "\n";
return 0;
}
老师的代码👇
http://gist.github.com/mycodeschool/7867739
这次状态不太好,写的可能不够清晰非常抱歉/(ㄒoㄒ)/~~我等过几天在自己看看,不行的话需要在编辑修改一下。
如果有问题欢迎指出,非常感谢!!
也欢迎交流建议哦。