[C++]Dijkstra's two-stack algorithm 计算简单算术表达式

Dijkstra's two-stack algorithm. 计算简单算术表达式

测试用例要求

说明:  数值、运算符以及括号必须显式地使用空白隔开。
      并且,一组括号里只能进行一次运算:
      例如 ( 1 + 2 + 3 ) 必须被写成 ( 1 + ( 2 + 3 ) ) ;

测试用例及输出结果

  • Win 按下 Cirtl+Z 表示输入结束;
  • 使用 cout101.0 表示成了 101

中缀表达式用例

中缀表达式用例 ( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
( 1 + ( ( 2 + 3 ) * ( 4 * 5 ) ) )
^Z
101

后缀表达式用例

后缀表达式用例 ( 1 ( ( 2 3 + ) ( 4 5 * ) * ) + ) .jpg
( 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,517评论 0 38
  • 英国工业革命始于18世纪60年代,这次工业革命的形成大致经历了一百年的时间,影响且推动了西欧北美地区的技术革新,范...
    独木桥_晴阅读 2,541评论 0 5
  • 当我为了一个人在凌晨两点还辗转反侧,打开手机微信上收到凌晨一点另一个人发给我的语音,可我无心回复。我觉得,我应该向...
    MorningScarlett阅读 315评论 0 0
  • 1898年的绍兴,青石巷里荷花香飘十里,十几岁的鲁迅在三味书屋读着线装书。 晚清的绍兴茶楼人声鼎沸,茶馆里的说书人...
    奋斗青年水淋儿阅读 862评论 0 1