表达式转换(改进版)

本文是基于博客表达式转换-CSDN博客的改进。
在上面博客讲到,表达式转换的一般思路为

  1. 初始化一个空的操作数栈,用于存放操作符。
  2. 从左到右扫描中缀表达式的每一个元素。
  3. 如果遇到的是操作数,数字,则直接添加到输出队列的末尾。
  4. 如果遇到操作符+-*/,则做以下处理:
    1. 将栈顶元素弹出并添加到输出队列,知道栈顶的操作符优先级低于或等于当前操作符的优先级。
    2. 将当前操作符压入栈中。
  5. 如果遇到左括号,压入栈中。
  6. 如果遇到右括号,则从栈中弹出操作符并添加到输出队列,知道遇到左括号为止,此时,将左括号从栈中移除,但不添加到输出队列。
  7. 当所有表达式的所有元素都处理完了后,将栈中剩余操作符一次弹出并添加到输出队列,直到为空。

代码为:

#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;
}

上述代码并不能包含所有的表达式情况,比如

  1. 当减号为一元运算符作为负号时,代码结果就会不正确;
  2. 当表达式有小数存在的情况。

为了解决这个问题,我们需要逐个考虑。

  1. 对于负号作为一元运算符,无非就是跟在左括号'('后面,还有就是作为表达式开头;
  2. 当有小数情况时,可以直接将小数点'.'直接加入字符串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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值