代码清单

  1. // binarytree.h
  2. #ifndef BINARYTREE_H
  3. #define BINARYTREE_H
  4.  
  5. template <typename T> class BinaryTree;
  6.  
  7. template <typename T>
  8. class BinaryTreeNode
  9. {
  10. public:
  11. friend class BinaryTree<T>;
  12. friend class Calculator;
  13. T _data;
  14.  
  15. private:
  16. BinaryTreeNode<T> * _leftChild;
  17. BinaryTreeNode<T> * _rightChild;
  18. };
  19.  
  20. template <typename T>
  21. class BinaryTree
  22. {
  23. public:
  24. BinaryTree()
  25. {
  26. _root = nullptr;
  27. }
  28.  
  29. ~BinaryTree()
  30. {
  31. destory();
  32. }
  33.  
  34. void preOrder()
  35. {
  36. preOrder(_root);
  37. }
  38.  
  39. void inOrder()
  40. {
  41. inOrder(_root);
  42. }
  43.  
  44. void postOrder()
  45. {
  46. postOrder(_root);
  47. }
  48.  
  49. protected:
  50. BinaryTreeNode<T> * _root;
  51.  
  52. void destory()
  53. {
  54. if (_root)
  55. {
  56. destory(_root);
  57. delete _root;
  58. }
  59. }
  60.  
  61. void destory(BinaryTreeNode<T> * node)
  62. {
  63. if (node)
  64. {
  65. destory(node->_leftChild);
  66. destory(node->_rightChild);
  67. // visit binary tree data
  68. if (node->_leftChild)
  69. {
  70. delete node->_leftChild;
  71. }
  72. if (node->_rightChild)
  73. {
  74. delete node->_rightChild;
  75. }
  76. }
  77. }
  78.  
  79. virtual void preOrder(BinaryTreeNode<T> * node)
  80. {
  81. if (node)
  82. {
  83. // visit binary tree data
  84. preOrder(node->_leftChild);
  85. preOrder(node->_rightChild);
  86. }
  87. }
  88.  
  89. virtual void inOrder(BinaryTreeNode<T> * node)
  90. {
  91. if (node)
  92. {
  93. inOrder(node->_leftChild);
  94. // visit binary tree data
  95. inOrder(node->_rightChild);
  96. }
  97. }
  98.  
  99. virtual void postOrder(BinaryTreeNode<T> * node)
  100. {
  101. if (node)
  102. {
  103. postOrder(node->_leftChild);
  104. postOrder(node->_rightChild);
  105. // visit binary tree data
  106. }
  107. }
  108. };
  109.  
  110. #endif // BINARYTREE_H
  111.  
  112. // calculator.h
  113. #ifndef CALCULATOR_H
  114. #define CALCULATOR_H
  115.  
  116. #include <cassert>
  117. #include <string>
  118. #include <stack>
  119. #include <iostream>
  120. #include "binarytree.h"
  121.  
  122. using namespace std;
  123.  
  124. typedef enum
  125. {
  126. BEGIN,
  127. NUMBER,
  128. OPERATOR,
  129. LEFT_BRAC,
  130. RIGHT_BRAC
  131. } TokenType;
  132.  
  133. class Token
  134. {
  135. public:
  136. TokenType _type;
  137. union
  138. {
  139. char op;
  140. double num;
  141. } _data;
  142. };
  143.  
  144. class Calculator : public BinaryTree<Token>
  145. {
  146. public:
  147. void parseExpression(string expression) throw(string);
  148. double calculate();
  149.  
  150. private:
  151. stack<char> _stkOperators;
  152. stack<BinaryTreeNode<Token> *> _stkNodes;
  153. stack<double> _stkNumbers;
  154.  
  155. static int priority(char op);
  156. static double calculate(double d1, char op, double d2) throw(string);
  157.  
  158. void postOrder(BinaryTreeNode<Token> * node);
  159. void calculateStack() throw(string);
  160. void dealWithNumber(char *&pToken) throw(string);
  161. void dealWithOperator(char *&pToken) throw(string);
  162. void dealWithLeftBrac(char *&pToken) throw(string);
  163. void dealWithRightBrac(char *&pToken) throw(string);
  164. };
  165.  
  166. #endif // CALCULATOR_H
  167.  
  168. // calculator.cpp
  169. #include "calculator.h"
  170.  
  171. int Calculator::priority(char op)
  172. {
  173. assert(op == '+' || op == '-' || op == '*' || op == '/' || op == '(');
  174.  
  175. if (op == '+' || op == '-')
  176. {
  177. return ;
  178. }
  179. else if (op == '*' || op == '/')
  180. {
  181. return ;
  182. }
  183. else
  184. {
  185. return ;
  186. }
  187. }
  188.  
  189. double Calculator::calculate(double d1, char op, double d2) throw(string)
  190. {
  191. assert(op == '+' || op == '-' || op == '*' || op =='/');
  192.  
  193. cout << d1 << op << d2 << endl;
  194.  
  195. if (op == '+')
  196. {
  197. return d1 + d2;
  198. }
  199. else if (op == '-')
  200. {
  201. return d1 - d2;
  202. }
  203. else if (op == '*')
  204. {
  205. return d1 * d2;
  206. }
  207. else
  208. {
  209. if (!d2)
  210. {
  211. throw string("divided by 0");
  212. }
  213. return d1 / d2;
  214. }
  215. }
  216.  
  217. void Calculator::calculateStack() throw(string)
  218. {
  219. BinaryTreeNode<Token> * node = new BinaryTreeNode<Token>();
  220. assert(node);
  221. node->_data._type = OPERATOR;
  222. node->_data._data.op = _stkOperators.top();
  223. _stkOperators.pop();
  224. assert(!_stkNodes.empty());
  225. node->_rightChild = _stkNodes.top();
  226. _stkNodes.pop();
  227. assert(!_stkNodes.empty());
  228. node->_leftChild = _stkNodes.top();
  229. _stkNodes.pop();
  230. _stkNodes.push(node);
  231. }
  232.  
  233. void Calculator::parseExpression(string expression) throw(string)
  234. {
  235. destory();
  236. while (!_stkNodes.empty())
  237. {
  238. _stkNodes.pop();
  239. }
  240. while (!_stkOperators.empty())
  241. {
  242. _stkOperators.pop();
  243. }
  244. TokenType lastToken = BEGIN;
  245.  
  246. char * pToken = &expression[];
  247. while (*pToken)
  248. {
  249. switch (lastToken)
  250. {
  251. case BEGIN:
  252. if (*pToken == '(')
  253. {
  254. // an expression begin with a left bracket
  255. dealWithLeftBrac(pToken);;
  256. lastToken = LEFT_BRAC;
  257. }
  258. else
  259. {
  260. // or a number
  261. dealWithNumber(pToken);
  262. lastToken = NUMBER;
  263. }
  264. break;
  265. case NUMBER:
  266. // after a number
  267. if (*pToken == ')')
  268. {
  269. // it may be a right bracket
  270. dealWithRightBrac(pToken);
  271. lastToken = RIGHT_BRAC;
  272. }
  273. else
  274. {
  275. // it may be an operator
  276. dealWithOperator(pToken);
  277. lastToken = OPERATOR;
  278. }
  279. break;
  280. case OPERATOR:
  281. case LEFT_BRAC:
  282. // after an operator or a left bracket
  283. if (*pToken == '(')
  284. {
  285. // it may be a left bracket
  286. dealWithLeftBrac(pToken);
  287. lastToken = LEFT_BRAC;
  288. }
  289. else
  290. {
  291. // it may be a number
  292. dealWithNumber(pToken);
  293. lastToken = NUMBER;
  294. }
  295. break;
  296. case RIGHT_BRAC:
  297. // after a right bracket
  298. if (*pToken == ')')
  299. {
  300. // it may be another right bracket
  301. dealWithRightBrac(pToken);
  302. lastToken = RIGHT_BRAC;
  303. }
  304. else
  305. {
  306. // it may be an perator
  307. dealWithOperator(pToken);
  308. lastToken = OPERATOR;
  309. }
  310. break;
  311. }
  312. }
  313.  
  314. while (!_stkOperators.empty())
  315. {
  316. if (_stkOperators.top() == '(')
  317. {
  318. throw string("bad token '('");
  319. }
  320. calculateStack();
  321. }
  322.  
  323. assert(!_stkNodes.empty());
  324. _root = _stkNodes.top();
  325. }
  326.  
  327. void Calculator::postOrder(BinaryTreeNode<Token> *node)
  328. {
  329. if (node)
  330. {
  331. postOrder(node->_leftChild);
  332. postOrder(node->_rightChild);
  333. // visit binary tree data
  334. if (node->_data._type == NUMBER)
  335. {
  336. _stkNumbers.push(node->_data._data.num);
  337. }
  338. else
  339. {
  340. assert(!_stkNumbers.empty());
  341. double d2 = _stkNumbers.top();
  342. _stkNumbers.pop();
  343. assert(!_stkNumbers.empty());
  344. double d1 = _stkNumbers.top();
  345. _stkNumbers.pop();
  346. char op = node->_data._data.op;
  347. _stkNumbers.push(calculate(d1, op, d2));
  348. }
  349. }
  350. }
  351.  
  352. double Calculator::calculate()
  353. {
  354. while (!_stkNumbers.empty())
  355. {
  356. _stkNumbers.pop();
  357. }
  358.  
  359. BinaryTree::postOrder();
  360.  
  361. assert(!_stkNumbers.empty());
  362. return _stkNumbers.top();
  363. }
  364.  
  365. void Calculator::dealWithNumber(char *&pToken) throw(string)
  366. {
  367. if (!isdigit(*pToken) && *pToken != '-')
  368. {
  369. throw string("bad token '") + *pToken + "'";
  370. }
  371.  
  372. BinaryTreeNode<Token> * node = new BinaryTreeNode<Token>();
  373. assert(node);
  374. node->_data._type = NUMBER;
  375. node->_data._data.num = strtod(pToken, &pToken);
  376. node->_leftChild = node->_rightChild = nullptr;
  377. _stkNodes.push(node);
  378. }
  379.  
  380. void Calculator::dealWithOperator(char *&pToken) throw(string)
  381. {
  382. if (*pToken != '+' && *pToken != '-' && *pToken != '*' && *pToken != '/')
  383. {
  384. throw string("bad token '") + *pToken + "'";
  385. }
  386.  
  387. if (!_stkOperators.empty()
  388. && priority(_stkOperators.top()) >= priority(*pToken))
  389. {
  390. calculateStack();
  391. }
  392. _stkOperators.push(*pToken++);
  393. }
  394.  
  395. void Calculator::dealWithLeftBrac(char *&pToken) throw(string)
  396. {
  397. if (*pToken != '(')
  398. {
  399. throw string("bad token '") + *pToken + "'";
  400. }
  401.  
  402. _stkOperators.push(*pToken++);
  403. }
  404.  
  405. void Calculator::dealWithRightBrac(char *&pToken) throw(string)
  406. {
  407. if (*pToken != ')')
  408. {
  409. throw string("bad token '") + *pToken + "'";
  410. }
  411.  
  412. while (!_stkOperators.empty() && _stkOperators.top() != '(')
  413. {
  414. calculateStack();
  415. if (_stkOperators.empty())
  416. {
  417. throw string("bad token ')'");
  418. }
  419. }
  420. _stkOperators.pop();
  421. pToken++;
  422. }
  423.  
  424. // main.cpp
  425. #include "calculator.h"
  426.  
  427. int main(int argc, char *argv[])
  428. {
  429. Calculator calculator;
  430.  
  431. if (argc > )
  432. {
  433. if (argc == )
  434. {
  435. calculator.parseExpression(string(argv[]));
  436. cout << calculator.calculate() << endl;
  437. }
  438. else
  439. {
  440. cout << "too many arguments" << endl;
  441. }
  442. }
  443. else
  444. {
  445. while ()
  446. {
  447. string expression;
  448. cout << ">" << flush;
  449. cin >> expression;
  450. if (expression == "quit;")
  451. {
  452. cout << "Bye." << endl;
  453. return ;
  454. }
  455. try
  456. {
  457. calculator.parseExpression(expression);
  458. cout << calculator.calculate() << endl;
  459. }
  460. catch (string ex)
  461. {
  462. cout << ex << endl;
  463. }
  464. }
  465. }
  466. }

表达式求值(二叉树方法/C++语言描述)(四)的更多相关文章

  1. 表达式求值(二叉树方法/C++语言描述)(二)

    表达式二叉树节点的数据可能是运算数或运算符,可以使用一个联合体进行存储:同时还需要一个变量来指示存储的是运算数还是运算符,可以采用和栈方法求值中一样的枚举类型TokenType: typedef en ...

  2. 表达式求值(二叉树方法/C++语言描述)(一)

    使用二叉树对算数表达式(以下简称为表达式)进行求值,实质上是将表达式转换为二叉树,对其进行后序遍历,得到后缀表达式的同时可以求得表达式的值.转换和求值的过程也需要借助数据结构栈的帮助. 二叉树数据结构 ...

  3. 表达式求值(二叉树方法/C++语言描述)(三)

    二叉树方法求值对运算数处理的方法与栈方法求值不太相同,除了将字符串中的运算数转换为浮点类型外,还需要生成新的节点: void Calculator::dealWithNumber(char *& ...

  4. 表达式求值(二叉树方法/C++语言描述)(五)

    本例中的二叉树图是使用Graphviz绘制的(Graphviz官网),在Ubuntu Linux下可以使用apt-get命令安装它: sudo apt-get install graphviz 表达式 ...

  5. 表达式求值--数据结构C语言算法实现

    这篇博客介绍的表达式求值是用C语言实现的,只使用了c++里面的引用. 数据结构课本上的一个例题,但是看起来很简单,实现却遇到了很多问题. 这个题需要构建两个栈,一个用来存储运算符OPTR, 一个用来存 ...

  6. LeetCode:逆波兰表达式求值【150】

    LeetCode:逆波兰表达式求值[150] 题目描述 根据逆波兰表示法,求表达式的值. 有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式. 说明: 整数除 ...

  7. 表达式求值(栈方法/C++语言描述)(二)

    上篇中完成了对表达式求值的整体过程,接下来看看如何处理不同类型的token. 对运算数的处理比较简单,它直接调用函数strtod(),将字符串中的运算数转换为浮点类型并将它压入运算数栈中: void ...

  8. 利用栈实现算术表达式求值(Java语言描述)

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

  9. Java描述表达式求值的两种解法:双栈结构和二叉树

    Java描述表达式求值的两种解法:双栈结构和二叉树 原题大意:表达式求值 求一个非负整数四则混合运算且含嵌套括号表达式的值.如: # 输入: 1+2*(6/2)-4 # 输出: 3.0 数据保证: 保 ...

随机推荐

  1. URLWRITE视图重写技术

    UrlRewrite就是地址重写,用户得到的全部都是经过处理后的URL地址,类似于Apache的mod_rewrite.将我们的动态网页地址转化为静态的地址,如html.shtml,还可以隐藏网页的真 ...

  2. 【PHP】最详细PHP从入门到精通(四)——PHP中的字符串

     PHP从入门到精通 之PHP中的字符串 大家好,继续跟进PHP最详尽的知识更新,本周,跟大家重点讲一下PHP中字符串的使用.在PHP中,字符串是非常重要的一个概念,基本上大家想到的字符串的处理功能, ...

  3. 【知识整理】这可能是最好的RxJava 2.x 入门教程(四)

    这可能是最好的RxJava 2.x入门教程系列专栏 文章链接: 这可能是最好的RxJava 2.x 入门教程(一) 这可能是最好的RxJava 2.x 入门教程(二) 这可能是最好的RxJava 2. ...

  4. 关于php的一些安全知识

    绝不要以明文形式显示或发送密码.即使是对密码的所有者也应该这样.如果你需要 "忘记密码" 的功能,可以随机生成一个新的 一次性的(这点很重要)密码,然后把这个密码发送给用户 你希望 ...

  5. EntityFramework.Extended.Update.Ambiguous column name

    异常描述 c#代码 dbcontext.Table.Where(x => x.B > 0).Update( x => new Table() { A = x.B } )  抛出异常: ...

  6. WCF学习——构建第二个WCF应用程序(六)

    一.创建客户端应用程序 若要创建客户端应用程序,你将另外添加一个项目,添加对该项目的服务引用,配置数据源,并创建一个用户界面以显示服务中的数据.若要创建客户端应用程序,你将另外添加一个项目,添加对该项 ...

  7. MySQL基础语法命令

    1. 建表 创建MySQL数据表需要以下信息: 表名 表字段名 定义每个表字段 通用语法: CREATE TABLE table_name (column_name column_type); 实例: ...

  8. 从Java熟练到Android入门

    刚刚从学校出来,唉,从Java转入Android. 当初老师告诉我们Android不重要,结果,Android的所有课不是在玩手机就是在说话,没认真听也没认真看,作业也没认真做,现在想想好后悔啊,以至 ...

  9. Lniux下安装mysql----编译版

    ####安装mysql-5.7.10rpm -e --nodeps mysqlrpm -e mysqlclient10useradd -g mysql -s /sbin/nologininstall_ ...

  10. Vue.js入学教程

    Vue.js是什么Vue.js 是用于构建交互式的 Web 界面的库.Vue.js 提供了 MVVM 数据绑定和一个可组合的组件系统,具有简单.灵活的 API.Vue.js(类似于view)是一套构建 ...