本文是基于博客表达式转换-CSDN博客的改进。
在上面博客讲到,表达式转换的一般思路为
- 初始化一个空的操作数栈,用于存放操作符。
- 从左到右扫描中缀表达式的每一个元素。
- 如果遇到的是操作数,数字,则直接添加到输出队列的末尾。
- 如果遇到操作符+-*/,则做以下处理:
- 将栈顶元素弹出并添加到输出队列,知道栈顶的操作符优先级低于或等于当前操作符的优先级。
- 将当前操作符压入栈中。
- 如果遇到左括号,压入栈中。
- 如果遇到右括号,则从栈中弹出操作符并添加到输出队列,知道遇到左括号为止,此时,将左括号从栈中移除,但不添加到输出队列。
- 当所有表达式的所有元素都处理完了后,将栈中剩余操作符一次弹出并添加到输出队列,直到为空。
代码为:
#include<iostream>
using namespace std;
// 运算符优先级
int priority(char op) {
if (op == '+' || op == '-') return 1;
if (op == '*' || op == '/') return 2;
return 0; // 其他情况比如括号
}
// 判断是否为运算符
bool isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
class Stack { // 栈类
private:
int top;
public:
char data[20]; //不超过20个字符
Stack() { top = -1; }//构造函数
bool isEmpty() { return top == -1; }
void push(char ch) { data[++top] = ch; }
char pop() { return data[top--]; }
char Top() { return data[top]; }
};
string getsuffix(string& infix) {
string suffix;
Stack s;
// 遍历中缀表达式,如果是数字,加入后缀表达式;
// 如果是运算符,判断优先级,如果栈中元素大于或等于当前运算符,弹出栈顶元素,否则压入栈;
// 如果遇到右括号,弹出栈中元素,直到遇到左括号,左括号不加入后缀表达式。
for (char ch : infix)
{
if (isalnum(ch)) { //数字或字母
suffix += ch;
suffix += ' ';
}
else if (ch == '(') { //左括号
s.push(ch);
}
else if (ch == ')') { //右括号
while (!s.isEmpty() && s.Top() != '(') {
suffix += s.pop();
suffix += ' ';
}
s.pop();//弹出左括号,不加入后缀表达式
}
else if (isOperator(ch)) {
//弹出大于等于当前优先级的运算符
while (!s.isEmpty() && priority(s.Top()) >= priority(ch)) {
suffix += s.pop();
suffix += ' ';
}
s.push(ch);//压入当前运算符
}
}
//将剩余的运算符加入后缀表达式
while (!s.isEmpty()) {
suffix += s.pop();
suffix += ' ';
}
//去掉最后一个空格
if (!suffix.empty()) {
suffix.pop_back();
}
return suffix;
}
int main() {
cout << "请输入中缀算术表达式:" << endl;
string infix;
cin >> infix;
cout << "后缀表达式为:" << endl << getsuffix(infix) ;
return 0;
}
上述代码并不能包含所有的表达式情况,比如
- 当减号为一元运算符作为负号时,代码结果就会不正确;
- 当表达式有小数存在的情况。
为了解决这个问题,我们需要逐个考虑。
- 对于负号作为一元运算符,无非就是跟在左括号'('后面,还有就是作为表达式开头;
- 当有小数情况时,可以直接将小数点'.'直接加入字符串suffix中。
下面是完整的代码:
#include<iostream>
using namespace std;
// 运算符优先级
int priority(char op) {
if (op == '+' || op == '-' ) return 1;
if (op == '*' || op == '/') return 2;
return 0; // 其他情况比如括号
}
// 判断是否为运算符
bool isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
class Stack { // 栈类
private:
int top;
public:
char data[20]; //不超过20个字符
Stack() { top = -1; }//构造函数
bool isEmpty() { return top == -1; }
void push(char ch) { data[++top] = ch; }
char pop() { return data[top--]; }
char Top() { return data[top]; }
};
string getsuffix(string& infix) {
string suffix;
Stack s;
// 遍历中缀表达式,如果是数字,加入后缀表达式;
// 如果是运算符,判断优先级,如果栈中元素大于或等于当前运算符,弹出栈顶元素,否则压入栈;
// 如果遇到右括号,弹出栈中元素,直到遇到左括号,左括号不加入后缀表达式。
char temp = infix[0]; //存下第一个元素,是为了判断负号是否在第一个位置
for (int i = 0; i < infix.size(); i++)
{
char ch = infix[i];
if (isalnum(ch) || ch == '.') { //数字或字母或小数
if(isalnum(infix[i+1]) || infix[i+1] == '.')
{
suffix += ch;
}
else
{
suffix += ch;
suffix += ' ';
}
}
else if (ch == '(') { //左括号
s.push(ch);
}
else if (ch == ')') { //右括号
while (!s.isEmpty() && s.Top() != '(') {
suffix += s.pop();
suffix += ' ';
}
s.pop();//弹出左括号,不加入后缀表达式
}
else if(temp == '-' || temp == '+' )
{
suffix += temp;
temp = '@';
}
else if((ch == '-' && infix[i-1] == '(') || (ch == '+' && infix[i-1] == '('))
{
suffix += ch;
}
else if (isOperator(ch)) {
//弹出大于等于当前优先级的运算符
while (!s.isEmpty() && priority(s.Top()) >= priority(ch)) {
suffix += s.pop();
suffix += ' ';
}
s.push(ch);//压入当前运算符
}
}
//将剩余的运算符加入后缀表达式
while (!s.isEmpty()) {
suffix += s.pop();
suffix += ' ';
}
//去掉最后一个空格
if (!suffix.empty()) {
suffix.pop_back();
}
return suffix;
}
int main() {
// cout << "请输入中缀算术表达式:" << endl;
string infix;
cin >> infix;
cout<<getsuffix(infix) ;
return 0;
}