学习目标:
例如:通过题目再次理解栈的使用学习内容:
题目:将仅含有+、-、×、÷、(、)以及小写字母的数学表达式转为但运算符和两个操作数的系列计算算式。例如:a+b*(c+d/a-e)-f
D1 = d/a
D2 = c+D1
D3 = D2-e
D4 = b*D3
D5 = a+D4
D6 = D5-f
中缀表达式、后缀表达式、前缀表达式
本题引入三个基本概念
中缀表达式:
(或中缀记法)是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间(例:3 + 4)。与前缀表达式(例:+ 3 4 )或后缀表达式(例:3 4 + )相比,中缀表达式不容易被电脑解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,中缀记法中括号是必需的。计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。维基百科
后缀表达式
逆波兰记法中,操作符置于操作数的后面。例如表达“三加四”时,写作“3 4 + ”,而不是“3 + 4”。如果有多个操作符,操作符置于第二个操作数的后面,所以常规中缀记法的“3 - 4 + 5”在逆波兰记法中写作“3 4 - 5 + ”:先3减去4,再加上5。使用逆波兰记法的一个好处是不需要使用括号。例如中缀记法中“3 - 4 * 5”与“(3 - 4)*5”不相同,但后缀记法中前者写做“3 4 5 * - ”,无歧义地表示“3 (4 5 *) -”;后者写做“3 4 - 5 * ”。
维基百科
前缀表达式
波兰表示法(Polish notation,或波兰记法),是一种逻辑、算术和代数表示方法,其特点是操作符置于操作数的前面,因此也称做前缀表示法。如果操作符的元数(arity)是固定的,则语法上不需要括号仍然能被无歧义地解析。波兰记法是波兰数学家扬·武卡谢维奇1920年代引入的,用于简化命题逻辑。
表达“三加四”时,前缀记法写作“+ 3 4 ”,而不是“3 + 4”。在复杂的表达式中,操作符仍然在操作数的前面,但操作数可能是包含操作符的平凡表达式。 例如,中缀运算式(5 - 6) * 7 ,在前缀表达式中可以表示为:
∗ ( − 56 ) 7 *(− 5 6) 7 ∗(−56)7
或省略括号:
∗ − 567 * - 5 6 7 ∗−567
由于简单的算术运算符都是二元的,该前缀表达式无需括号,且表述是无歧义的。在前面的例子里,中缀形式的括号是必需的,如果将括号移动到:
5 − ( 6 ∗ 7 ) 5 - (6 * 7) 5−(6∗7)
即:
5 − 6 ∗ 7 5 - 6 * 7 5−6∗7
则会改变整个表达式的值。而其正确的前缀形式是:
− 5 ∗ 67 - 5 * 6 7 −5∗67
减法运算要等它的两个操作数(5;6和7的乘积)都完成时才会处理。在任何表示法中,最里面的表达式最先运算,而在波兰表达式中,决定“最里面”的是顺序而不是括号。
简单算术的前缀表达式主要是用于学术研究方面。与逆波兰表示法不同,前缀表达式基本没有在商业计算器中使用过,但是其体系经常在编译器构造的概念教学中首先使用。维基百科
实现
表达式求值问题实现——中缀表达式转后缀表达式
#include <string>
#include <iostream>
#include <stack>
#include <map>
#include <vector>
using namespace std;
map<char, int> compare;
bool compareFunc(char in1, char in2){
return compare[in1] >= compare[in2];
}
int main()
{
compare['+'] = 1;
compare['-'] = 1;
compare['*'] = 2;
compare['/'] = 2;
stack<char> optRt;
stack<char> optND;
vector<string> ret;
string example = "a+b*(c+d/a-e)-f";
int i = 0;
int ans = 0;
int length = example.size();
while(i < length){
char tmp = example[i++];
if(tmp >= 'a' && tmp <= 'z'){
optND.push(tmp);
}else{
if(tmp == ')'){
char in_opt = optRt.top();
optRt.pop();
while(in_opt != '('){
string one_expr;
one_expr.push_back('D');
one_expr.push_back('0'+ans);
one_expr.push_back('=');
char opt_num1 = optND.top();
optND.pop();
char opt_num2 = optND.top();
one_expr.push_back(opt_num2);
cout << "while('(') --> in_opt: " << in_opt << endl;
one_expr.push_back(in_opt);
one_expr.push_back(opt_num1);
optND.pop();
optND.push('0'+ans);
ret.push_back(one_expr);
++ans;
in_opt = optRt.top();
optRt.pop();
}
}else if(tmp == '('){
optRt.push(tmp);
}else{
if(optRt.size() == 0){
optRt.push(tmp);
continue;
}
char in_opt = optRt.top();
string one_expr;
if(compareFunc(in_opt, tmp)){
optRt.pop();
optRt.push(tmp);
string one_expr;//注释掉
one_expr.push_back('D');
one_expr.push_back('0'+ans);
one_expr.push_back('=');
char opt_num1 = optND.top();
optND.pop();
char opt_num2 = optND.top();
one_expr.push_back(opt_num2);
cout << "in_opt: " << in_opt << endl;
one_expr.push_back(in_opt);
one_expr.push_back(opt_num1);
optND.pop();
optND.push('0'+ans);
ret.push_back(one_expr);
++ans;
in_opt = optRt.top();
// optRt.pop();
}else{
optRt.push(tmp);
}
}
}
}
while(optRt.size()){
char in_opt = optRt.top();
optRt.pop();
string one_expr;//注释掉
one_expr.push_back('D');
one_expr.push_back('0'+ans);
one_expr.push_back('=');
char opt_num1 = optND.top();
optND.pop();
char opt_num2 = optND.top();
one_expr.push_back(opt_num2);
cout << "in_opt: " << in_opt << endl;
one_expr.push_back(in_opt);
one_expr.push_back(opt_num1);
optND.pop();
optND.push('0'+ans);
ret.push_back(one_expr);
++ans;
}
for(auto& it : ret){
cout << it << endl;
}
return 0;
}
学习时间:
提示:这里可以添加计划学习的时间
例如:
1、 周一至周五晚上 7 点—晚上9点
2、 周六上午 9 点-上午 11 点
3、 周日下午 3 点-下午 6 点