中缀表达式求值(C++版本 含详细注释)

看了一圈回答,大部分代码要么只能读取0到9的数,要么引了一堆复杂的STL,主体内容冗长可读性低,希望我的这一版能弥补一些缺陷,对你有所帮助。

中缀表达式处理的关键在于处理好括号,保证括号内的运算能优先进行。用一个字符栈保存运算符、一个数字栈(这里采用vector动态数组,因为方便修改末尾元素)保存运算结果。

主要步骤如下:

输入中缀表达式,从头开始遍历,若当前字符为开括号,直接入字符栈;

若当前字符为闭括号,不断弹出字符栈顶运算符,直到栈顶为开括号,将其弹出;

若当前字符为数字,将其转化成整型后压栈,注意超过一位的数要用一个bool变量判断当前位x情况,用x的前一位*10+x来更新x的前一位,不管是几位数,压进去的还是一个数字。

若当前字符opt为运算符(目前仅限四则运算,如果还有乘方,它的优先级就是最高,弄个函数把每个运算符优先级划分好),比较opt和字符栈顶符号top,只要字符栈非空且栈顶元素不是开括号且优先级:top>=opt,就弹栈,然后同步弹出数字栈两个元素,做运算,结果再压回数字栈。结束以后把opt入字符栈。

当前表达式遍历完后如果字符栈还有元素,要全部弹完,一样是和数字栈的元素做运算,后者剩下的最后一个元素就是表达式的值。

注释写得很详细,其实不用看上面的步骤也能懂得差不多了。笔者写的时候在获取超过一位的数这里想了好久,后来根据看了一位大佬关于字符串提取的回答,学到了设置bool变量判断的方法。其实无论是什么缀表达式,数字出现的先后顺序是固定的,只要确定好运算符和数字结合的顺序,就能求出表达式值。用栈实现不过是为了满足后读取到的符号先拿出来计算这一原则罢了。

#include
#include
#include
#include
using namespace std;
int level(char a) {//返回运算符优先级
	int lev = 0;
	if (a == '+' || a == '-')
		lev = 1;
	else if (a == '*' || a == '/')
		lev = 2;
	return lev;
}
int cal(int x, int y, char opt) {//四则运算
	int ret = 0;
	if (opt == '+')	ret = x + y;
	else if (opt == '-')	ret = x - y;
	else if (opt == '*')	ret = x * y;
	else if (opt == '/')	ret = x / y;
	return ret;
}
void popCal(stack& s, vector& num) {//弹栈,做运算,再存栈
	char opt = s.top();//从运算符栈弹出opt
	s.pop();
	int y = num.back();//从动态数组(整数栈)末尾弹出两个整数和opt做运算
	num.pop_back();
	int x = num.back();
	num.pop_back();
	num.push_back(cal(x, y, opt));//运算结果压入整数栈中
}
int main() {
	stack s;//运算符栈
	vector num;//整数的动态数组(整数栈),最终剩下的一个数就是表达式的值
	string infix;//中缀表达式
	int n = 0;//表达式个数
	bool key = false;//判断当前数字是不是它的第一位
	cin >> n;
	int* data = new int[n];//储存每个表达式的值
	for (int k = 0; k < n; k++) {
		cin >> infix;
		for (int i = 0; i < infix.length(); i++) {
			if (infix[i] == '(') {
				if (key == true)	key = false;//另外三种情况下都要重置key
				s.push(infix[i]);
			}
			else if (infix[i] == ')') {
				if (key == true)	key = false;//另外三种情况下都要重置key
				if (s.empty()) {
					throw - 1;
					break;
				}
				else {
					while (s.top() != '(') {
						popCal(s, num);
						if (s.empty()) {
							throw - 1;
							break;
						}
					}
					s.pop();//把运算符栈中'('弹出
				}
			}
			else if (infix[i] == '+' || infix[i] == '-' || infix[i] == '*' || infix[i] == '/') {
				if (key == true)	key = false;//另外三种情况下都要重置key
				while (!s.empty() && s.top() != '(' && level(s.top()) >= level(infix[i]))
					popCal(s, num);
				s.push(infix[i]);//若栈顶是'(',默认输入运算符优先级最高,直接压栈
			}
			else {//扫描到数字时
				int tmp = infix[i] - '0';//字符转整型值
				if (key) //若不是第一位数
					*(num.end() - 1) = *(num.end() - 1) * 10 + tmp;//就用它更新整数栈顶的值
				else {
					num.push_back(tmp);//是第一位就压栈
					key = true;
				}
			}
		}
		while (!s.empty()) {
			popCal(s, num);
		}//符号栈为空才算完
		data[k] = num.back();
		num.pop_back();//一次表达式算完后清空数字栈
		key = false;
		infix.erase(infix.begin(),infix.end());//下一次输入前清空字符串
	}
	for (int i = 0; i < n; i++)
		cout << data[i] << endl;
	delete[] data;
}

你可能感兴趣的:(c++,数据结构)