题目描述
读入一个只包含加减乘除的非负整数计算表达式,并求解结果;
本题用来练习栈和队列的使用,核心是中缀表达式转后缀表达式;
输入格式
每次输入一行,整数和运算符之间用一个空格(或者可以不加)分隔;
输出格式
每次输出一行,精确到小数点后 2 位;
输入示例
30 / 90 - 26 + 97 - 5 - 6 - 13 / 88 * 6 + 51 / 29 + 79 * 87 + 57 * 92
输出示例
12178.21
思路
输入的格式为中缀表达式,需要计算结果需要以下两个步骤:
- 中缀表达式转后缀表达式;
- 计算后缀表达式;
中缀表达式是人类习惯使用的,但是后缀表达式和前缀表达式更适合计算机的计算过程。中缀表达式可以简单的理解为运算符放在两个操作数中间,但后缀表达式的运算符放在两个操作数之后,前缀即放在两个操作数之前,示例如下:
中缀表达式:3 + 2 * 6 / 3
后缀表达式:3 2 6 * 3 / +
前缀表达式:+ 3 / * 2 6 3
本次程序采用中缀表达式转后缀表达式;
中缀表达式转后缀表达式:
- 设立一个操作符栈 s ,用于临时存放操作符;设立一个队列 q ,用来存放后缀表达式
- 从左到右,扫描中缀表达式,每个字符使用包含操作符 op 、操作数 num 和选择项 flag 的结构体表示。此时需要注意两点:① 操作数可能不止一位,不能只关心个位数;② 操作前需要把中缀表达式中的空格全部删除;
- 如果碰到操作数,就将操作数加入后缀表达式 q 的 num 中,并把 flag 设为 true;如果碰到操作符(记为 op),就比较 op 与栈顶操作符 s.top() 的优先级,优先级排序为
乘法 == 除法 > 加法 == 减法
; - op 与 s.top() 优先级的比较规则如下:若 op 优先级大于 s.top(),将 op 压入 s;若 op 优先级小于 s.top(),将 s 栈顶弹出到后缀表达式 q 中,直到 op 的优先级大于 s.top() 或者 s 为空;
- 重复上述操作 3 和 4,直到中缀表达式扫描完毕,若 s 中仍有元素,将其依次弹出至 q 中;
计算后缀表达式
- 从左到右扫描后缀表达式,如果是操作数(
flag == true
),就压入栈 s,如果是操作符(flag == false
),就连续弹出两个操作数 temp2 和 temp1,但需要注意,先弹出的是 temp2,后弹出的是 temp1; - 将 temp1 和 temp2 与操作符运算,将计算结果重新压入栈 s,此时需要注意,操作结果需要用 double 型变量,因为除法操作可能出现非整除;
- 最后,栈 s 中仅剩一个数,这个数就是计算结果;
代码
#include <iostream>
#include <stdio.h>
#include <string>
#include <queue>
#include <stack>
#include <map>
using namespace std;
struct node{
double num; //操作数
char op; //操作符
bool flag; //选择操作数or操作符
};
string str; //存放中缀表达式的字符串
stack<node> s; //存放操作符的栈
queue<node> q; //存放后缀表达式
map<char, int> op; // 定义操作符的优先级,加减为1,乘除为2
void abbr(){
//删除空格
for(string::iterator it=str.begin();it!=str.end();it++){
if