Dijkstra's two-stack algorithm. 计算简单算术表达式
测试用例要求
说明: 数值、运算符以及括号必须显式地使用空白隔开。
并且,一组括号里只能进行一次运算:
例如 ( 1 + 2 + 3 ) 必须被写成 ( 1 + ( 2 + 3 ) ) ;
测试用例及输出结果
- Win 按下 Cirtl+Z 表示输入结束;
- 使用 cout , 101.0 表示成了 101;
中缀表达式用例
( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
^Z
101
后缀表达式用例
( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + )
^Z
101
--------------------------------
Process exited after 2.968 seconds with return value 0
请按任意键继续. . .
算法实现完整C++源码
/*********************************************************************
*
* 参考: https://algs4.cs.princeton.edu/13stacks/Evaluate.java.html
*
* 算法: Dijkstra's two-stack algorithm.
*
* 说明: 数值、运算符以及括号必须显式地使用空白隔开。
* 并且,一组括号里只能进行一次运算:
* 例如 ( 1 + 2 + 3 ) 必须被写成 ( 1 + ( 2 + 3 ) ) ;
*
* 用例 1 : ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
* 预期 1 : 101.0
*
* 用例 2 : ( ( 1 + sqrt ( 5 ) ) / 2.0 )
* 预期 2 : 1.618033988749895
*
* 注意: 本算法可以处理后缀表达式
* 用例 : ( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + )
* 预期 : 101.0
* 去掉括号就是后缀表达式 1 2 3 + 4 5 * * +
*
********************************************************************/
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
#include <cmath>
using namespace std;
double string_to_double( const std::string& s )
{
std::istringstream i(s);
double x;
if (!(i >> x))
return 0;
return x;
}
int main() {
stack<string> ops;
stack<double> vals;
string s;
while(cin >> s) {
if (s == "(") {}
else if (s == "+") { ops.push(s); }
else if (s == "-") { ops.push(s); }
else if (s == "*") { ops.push(s); }
else if (s == "/") { ops.push(s); }
else if (s == "sqrt") { ops.push(s); }
else if (s == ")") {
string op = ops.top(); ops.pop();
double v = vals.top(); vals.pop();
if (op == "+") { v = vals.top() + v; vals.pop(); }
else if (op == "-") { v = vals.top() - v; vals.pop(); }
else if (op == "*") { v = vals.top() * v; vals.pop(); }
else if (op == "/") { v = vals.top() / v; vals.pop(); }
else if (op == "sqrt") { v = sqrt(v); }
vals.push(v);
}
else vals.push(string_to_double(s));
}
cout << vals.top();
}
代码说明
- 我上面的C++版本实现,是照着 algs4 官网的 java 版本写的,连缩进格式都可以不改;
- 需要导入STL的 string stack 等;
- string 转换成 double 的 函数参考自Stack Overflow,关键就是用 sstream;
图解用例
- 《算法(第四版)》algs4 1.3 ■ Bags, Queues, and Stacks Dijkstra’s Two-Stack Algorithm for Expression Evaluation书上这一节给了完整的代码之后,就是非常漂亮、极其详细的用例图解,一看就明明白白;
算法过程
- - 两个栈,一个存运算符的 `ops `、一个存操作数的` vals `;
- - 遇到左括号,什么也不做;
- - 遇到右括号,就把 `vals `栈顶上的两个操作数进行对应的运算,
- - - 然后再把运算结果压入`vals`栈;
- - 直到读取完全部的符号,输入变空;
- - 用例的格式标准决定了 这时候 `vals`必然只剩下一个操作数,就是运算结果。
中缀表达式用例 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
( 1 + ( 5 * ( 4 * 5 ) ) )
( 1 + ( 5 * 20 ) )
( 1 + 100 )
101
- 对用例的要求非常高,操作数与运算符之间要有显式的空白符隔开;
- 一组括号只能对应一个操作符,才能保证输入完刚好计算完;
为什么也可以处理后缀表达式
中缀 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
后缀 ( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + )
大概是因为有一 一对应的括号组
代码改进
https://algs4.cs.princeton.edu/13stacks/EvaluateDeluxe.java.html
参考
https://algs4.cs.princeton.edu/13stacks/Evaluate.java.html
How can I convert string to double in C++?
https://stackoverflow.com/questions/37110903/dijkstras-two-stack-algorithm-for-expression-evaluation