栈的应用:表达式求值

0. 例题

编写一个程序可以完成基本的带括号的四则运算。其中除法(/)是整除,并且在负数除法时向0取整。(C/C++/Java默认的除法就是向0取整,python默认的是向负无穷取整)。
例如计算 100 * ( 2 + 12 ) - (20 / 3) * 2, 结果是1388
样例输入:
100*(2+12)-(20/3)*2
样例输出:
1388

1. 分析

中缀表达式将二元运算符放在两个操作数之间,而后缀表达式的每个运算符都出现在相应操作数之后。后缀表达式去掉了括号,因此在计算机中,用后缀表达式求值更为简单。
100*(2+12)-(20/3)*2为中缀表达式,其对应的后缀表达式(逆波兰式)为100&2&12+*20&3/2*-
用用后缀表达式求值是栈的典型应用,其步骤分为两步:

将中缀表达式转换为后缀表达式

数字:直接添加到后缀表达式中,数值之间需要添加分隔符
左括号:直接压入到符号栈。
右括号:右括号总是不入栈,遇到右括号,则之前入栈的运算符逐一出栈,并添加到后缀表达式中,直到碰到左括号。遇到左括号直接将其弹出即可
运算符:运算符入栈之前,与符号栈栈顶的运算符比较优先级,如果优先级小于或等于栈顶运算符优先级,则栈顶运算符弹出,并添加到后缀表达式中,最后将待入栈的运算符入栈(优先级比较时,左括号当作低优先级运算符处理)
中缀表达式循环一遍之后,最后将符号栈中的运算符逐一弹出,添加到后缀表达式中。

利用后缀表达式求值

数字:根据分隔符取出完整数值,压入到数值栈。数字处理注意如何将数字组合成完整的数值
运算符:弹出数值栈的栈顶前两个数值,与运算符一起进行四则运算,再将运算结果压入到数值栈,当到达后缀表达式末端时,数值栈中应该只有一个数值,该值即为整个表达式的运算结果。运算符处理时,注意除法中操作数的顺序

2. 中缀表达式转换为后缀表达式

//获取运算符优先级
int getRink(char opt){    
	if (opt == '+' || opt == '-') return 10;
	if (opt == '*' || opt == '/') return 20;
	if (opt == '(') return 0;
	else return -1;
}
//中缀表达式转为后缀表达式
//str_mid:中缀表达式
//str_post:后缀表达式
int postfix(string &str_post, string &str_mid){  
	stack<char> opt;   //定义运算符栈
	bool flag = false; //标记上一个输出是否为数字
	while (!opt.empty()) opt.pop();//运算符栈清空
	for (int i = 0; str_mid[i] != '\0'; i++){
		// 数字处理
		if (str_mid[i] >= '0' && str_mid[i] <= '9'){
			if (flag) str_post += '&'; //上一个输出为数字则中间用&分隔
			else flag = true;
			//获取一个数值中的连续多个数字
			while ('0' <= str_mid[i] && '9' >= str_mid[i]){
				str_post += str_mid[i];
				i++;
			}
			i--;
		}
		//左括号处理
		else if (str_mid[i] == '('){
			opt.push(str_mid[i]);
		}
		//右括号处理
		else if (str_mid[i] == ')'){
			while (opt.top() != '(' && !opt.empty()){
				str_post += opt.top();
				opt.pop();
				flag = false;
			}
			if (opt.empty()) return -1;
			if (opt.top() == '('){
				opt.pop();
			}
		}
		//运算符处理
		else if (str_mid[i] == '+' || str_mid[i] == '-' || str_mid[i] == '*' || str_mid[i] == '/'){
			int a1 = getRink(str_mid[i]);
			if (a1<0) return -1;
			int a2;
			while (!opt.empty()){
				a2 = getRink(opt.top());
				if (a2<0) return -1;
				if (a1 <= a2){ //等于的时候也要弹出
					str_post += opt.top();
					opt.pop();
					flag = false;
				}
				else break;
			}
			opt.push(str_mid[i]);
		}
		else return -1;
	}
	// 运算符出栈
	while (!opt.empty()){
		if (opt.top() == '(') return -1;
		str_post += opt.top();
		opt.pop();
	}
	return 0;
}

  

转载于:https://www.cnblogs.com/wuxubj/p/7088551.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值