1. package ch8;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import java.util.Stack;
  5. /**
  6. * 四则混合运算表达式计算
  7. * @author Jinjichao
  8. *
  9. */
  10. public class Calculator {
  11. /**
  12. * 运算符枚举
  13. * @author Jinjichao
  14. *
  15. */
  16. private enum Operator {
  17. ADD("+", 10), SUBTRACT("-", 10), MULTIPLY("*", 20), DIVIDE("/", 20),
  18. PARENTHESIS_LEFT("(", 100), PARENTHESIS_RIGHT(")", 100);
  19. private String operator;
  20. private int priority;
  21. private Operator(String operator, int priority) {
  22. this.operator = operator;
  23. this.priority = priority;
  24. }
  25. }
  26. /**
  27. * 操作数枚举
  28. * @author Jinjichao
  29. *
  30. */
  31. private enum Operand {
  32. ONE("1"), TWO("2"), THREE("3"), FOUR("4"), FIVE("5"), SIX("6"),
  33. SEVEN("7"), EIGHT("8"), NINE("9"), ZERO("0"), POINT(".");
  34. private String operand;
  35. private Operand(String operand) {
  36. this.operand = operand;
  37. }
  38. }
  39. /**
  40. * 获取字符串所对应的运算符枚举
  41. * @param str
  42. * @return
  43. */
  44. private Operator getOperator(String str) {
  45. for (Operator op : Operator.values()) {
  46. if (str.equals(op.operator)) {
  47. return op;
  48. }
  49. }
  50. return null;
  51. }
  52. /**
  53. * 获取字符串所对应的操作数枚举
  54. * @param str
  55. * @return
  56. */
  57. private Operand getOperand(String str) {
  58. for (Operand op : Operand.values()) {
  59. if (str.equals(op.operand)) {
  60. return op;
  61. }
  62. }
  63. return null;
  64. }
  65. /**
  66. * 第1步: 将运算表达式字符串分解为运算表达式List
  67. *
  68. * @param exp
  69. * @return
  70. */
  71. private List<String> resolveExpr(String exp) {
  72. List<String> list = new LinkedList<String>();
  73. String temp = "";
  74. exp = exp.replace(" ", "");
  75. for (int i = 0; i < exp.length(); i++) {
  76. String str = exp.substring(i, i + 1);
  77. Operator op = getOperator(str);
  78. Operand od = getOperand(str);
  79. if (op != null) {
  80. if (!temp.isEmpty()) {
  81. list.add(temp);
  82. temp = "";
  83. }
  84. list.add(str);
  85. } else if (od != null) {
  86. temp += str;
  87. } else {
  88. System.out.println("表达式[" + str + "]非法! ");
  89. return null;
  90. }
  91. }
  92. if (!temp.isEmpty()) {
  93. list.add(temp);
  94. }
  95. //System.out.println(list);
  96. return list;
  97. }
  98. /**
  99. * 第2步: 将运算表达式List转换为逆波兰表达式List
  100. * @param expList
  101. * @return
  102. */
  103. private List<String> dealExpr(List<String> expList) {
  104. if(expList == null) {
  105. return null;
  106. }
  107. List<String> list = new LinkedList<String>();
  108. Stack<String> stack = new Stack<String>();
  109. for (String str : expList) {
  110. Operator op = getOperator(str.substring(0, 1));
  111. Operand od = getOperand(str.substring(0, 1));
  112. if (od != null) {
  113. //操作数直接入队列
  114. list.add(str);
  115. } else if (op != null) {
  116. if (Operator.PARENTHESIS_LEFT.equals(op)) {
  117. //左括号入栈
  118. stack.push(str);
  119. } else if (Operator.PARENTHESIS_RIGHT.equals(op)) {
  120. //右括号: 循环将栈顶的运算符取出并存入队列,直到取出左括号
  121. while (true) {
  122. if (stack.empty()) {
  123. System.out.println("缺少左括号! ");
  124. return null;
  125. } else if (Operator.PARENTHESIS_LEFT.operator.equals(stack.peek())) {
  126. stack.pop();
  127. break;
  128. } else {
  129. list.add(stack.pop());
  130. }
  131. }
  132. } else {
  133. //非括号类运算符
  134. if (!stack.empty()) {
  135. Operator top_op = getOperator(stack.peek());
  136. //当前运算符优先级大于栈顶运算符优先级,或者栈顶为左括号时,当前运算符直接入栈
  137. if(op.priority > top_op.priority
  138. || Operator.PARENTHESIS_LEFT.equals(top_op)) {
  139. stack.push(str);
  140. }
  141. //否则,将栈顶的运算符取出并存入队列,然后将自己入栈
  142. else {
  143. list.add(stack.pop());
  144. stack.push(str);
  145. }
  146. } else {
  147. stack.push(str);
  148. }
  149. }
  150. }
  151. }
  152. while(!stack.empty()) {
  153. String str = stack.peek();
  154. if(Operator.PARENTHESIS_LEFT.operator.equals(str)) {
  155. System.out.println("缺少右括号! ");
  156. return null;
  157. } else {
  158. list.add(stack.pop());
  159. }
  160. }
  161. //System.out.println(list);
  162. return list;
  163. }
  164. /**
  165. * 操作数运算
  166. * @param x
  167. * @param y
  168. * @param op
  169. * @return
  170. */
  171. private String operation(String x, String y, Operator op) {
  172. double a = 0.0;
  173. double b = 0.0;
  174. try {
  175. a = Double.parseDouble(x);
  176. b = Double.parseDouble(y);
  177. } catch (NumberFormatException e) {
  178. System.out.println("操作数非法! ");
  179. e.printStackTrace();
  180. }
  181. switch (op) {
  182. case ADD:
  183. return String.valueOf(a + b);
  184. case SUBTRACT:
  185. return String.valueOf(a - b);
  186. case MULTIPLY:
  187. return String.valueOf(a * b);
  188. case DIVIDE:
  189. return String.valueOf(a / b);
  190. default:
  191. return null;
  192. }
  193. }
  194. /**
  195. * 第3步: 逆波兰表达式运算
  196. * @param exp
  197. * @return
  198. */
  199. public String calculate(String exp) {
  200. List<String> expList = dealExpr(resolveExpr(exp));
  201. if(expList == null) {
  202. return null;
  203. }
  204. Stack<String> stack = new Stack<String>();
  205. for(String str : expList) {
  206. Operator op = getOperator(str.substring(0, 1));
  207. Operand od = getOperand(str.substring(0, 1));
  208. if(od != null) {
  209. stack.push(str);
  210. } else if (op != null) {
  211. //目前仅针对二元运算符
  212. String x = "";
  213. String y = "";
  214. if(!stack.empty()) {
  215. y = stack.pop();
  216. }
  217. if(!stack.empty()) {
  218. x = stack.pop();
  219. }
  220. if(!x.isEmpty() && !x.isEmpty()) {
  221. String result = operation(x, y, op);
  222. if(result == null) {
  223. return null;
  224. }
  225. stack.push(result);
  226. } else {
  227. return null;
  228. }
  229. }
  230. }
  231. return stack.pop();
  232. }
  233. }

复制代码

测试一下:

  1. package ch8;
  2. /**
  3. * 测试
  4. * @author Jinjichao
  5. *
  6. */
  7. public class Test {
  8. public static void main(String[] args) {
  9. Calculator cal = new Calculator();
  10. String str = cal.calculate("( ( ( 15 / 3 ) + ( 1.5 * 2 ) + ( 20 - 12 ))  - 3.2 +2.3 + 5 ) ");
  11. System.out.println("运算结果:" + str);
  12. }
  13. }

复制代码

运行结果:
运算结果:20.1
其他的测试案例:

<IGNORE_JS_OP>

1.jpg (15.44 KB)

下载附件  保存到相册

2015-8-22 16:54 上传

 

<IGNORE_JS_OP>

2.jpg (16.65 KB)

下载附件  保存到相册

2015-8-22 16:54 上传

 

<IGNORE_JS_OP>

3.jpg (19.76 KB)

下载附件  保存到相册

2015-8-22 16:54 上传

 

算法原理(对照截图):
第1步、将表达式字符串分解为运算表达式List(将运算符和操作数分别分解出来)
第2步:将运算表达式List转换为逆波兰表达式List
第3步:逆波兰表达式运算

java 解析四则混合运算表达式并计算结果的更多相关文章

  1. 如何处理加括号的四则混合运算表达式——基于二叉树的实现(Eclipse平台 Java版)

    记得上<数据结构>课程时,利用栈的特性解决过四则混合运算表达式.而如今在编写小型关系数据库的时候,编译部分要处理where后面的逻辑表达式——检查语法正确与否的同时,还要将信息传给下一个接 ...

  2. C语言编程学习:写的秒速计算四则混合运算项目

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  3. 用C++实现的有理数(分数)四则混合运算计算器

    实现目标 用C++实现下图所示的一个console程序: 其中: 1.加减乘除四种运算符号分别用+.-.*./表示, + 和 - 还分别用于表示正号和负号. 2.分数的分子和分母以符号 / 分隔. 3 ...

  4. MathExamV2.0四则混合运算计算题生成器

    MathExamV2.0四则混合运算计算题生成器----211606360 丁培晖 211606343 杨宇潇 一.预估与实际 PSP2.1 Personal Software Process Sta ...

  5. 软件工程学习之小学四则混合运算出题软件 Version 1.00 设计思路及感想

    对于小学四则混合运算出题软件的设计,通过分析设计要求,我觉得为了这个软件在今后便于功能上的扩充,可以利用上学期所学习的<编译原理>一课中的LL1语法分析及制导翻译的算法来实现.这样做的好处 ...

  6. 带括号的四则混合运算的算符优先算法-----java实现

    1:主方法 package com.baidu; import java.text.NumberFormat;import java.util.ArrayList;import java.util.S ...

  7. 软件工程学习之小学四则混合运算出题软件 Version 1.1 设计思路及感想

    继上次采用形式文法来生成混合运算的算式,由于算法中没有引入控制参数而导致容易产生形式累赘(多余的括号等)的算式.本次更新决定采用一种更为简单有效的生成方式,由给出的一个随机的最终答案S,通过给定的一个 ...

  8. java 四则混合运算 计算器

    public class Counter { /**用递归算法,把括号内的公式算出然后递归   * @param args   */ public static void calculator (St ...

  9. web四则混合运算3

    一.程序要求: 可以控制下列参数: 是否有乘除法: 是否有括号(最多可以支持十个数参与计算): 数值范围: 加减有无负数: 除法有无余数!   二.设计思路 要求能够通过参数来控制有无乘除法,加减有无 ...

随机推荐

  1. oracle的日期蛋

    一切都是扯鸡巴蛋. 在网上查oracle的日期函数用法,得到一大堆语法,林林总总,都是扯鸡巴蛋,没能解决我的问题. 其实,我想写这么一条语句:查找某个日期(不含时分秒)产生或有关的记录.咋写? SQL ...

  2. while语句字符串的基本操作

    1,编码:对现在通用文字编码成计算机文字,便于储存,传递,交流. 最早的计算机编码是ACSII美国人创建的,包含英文字母,数字,以及特殊符号.总共是128个码位:2**7,因为计算机的底层只能识别:& ...

  3. jquery ui tabs详解(中文)

    1 属性1.11 ajaxOptions,当选项卡加载内容时,添加一个ajax选项.只有ajax时,添加的ajax选项才起作用.默认值为null.上面的例子中,添加了beforeSend和succes ...

  4. rabbitmq kafka storm

    rabbitmq:实时消息传递 kafka:消息的持久化 storm:使用拓扑逻辑进行

  5. jquery中的工具函数 Utilities

    noConflict(deep) 释放$和Jquery的控制权 isFunction(obj) isArray(obj) isWindow(obj) isNumeric(obj) type(obj) ...

  6. POJ1182 食物链 —— 种类并查集

    题目链接:http://poj.org/problem?id=1182 食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: ...

  7. 解决多次异步请求紊乱问题 - JavaScript

    加入目前的需求这样的:       左边的菜单链接,点击后通过异步请求返回其HTML代码,然后innerHTML到右面的DIV中,加入切换菜单的速度非常快,最终会导致请求紊乱. 可以加入消息管理机制, ...

  8. 一步一步学Silverlight 2系列(4):鼠标事件处理

    一步一步学Silverlight 2系列(4):鼠标事件处理   概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言V ...

  9. AutoIT: 下载文件函数

    Func down() $Size=InetGetSize($a[$j][]);获得FTP上的文件的大小 InetGet($a[$j][],$a[$j][],,);下载 ProgressOn(],), ...

  10. 13_传智播客iOS视频教程_OC程序的编译链接

    C程序的编译.链接.执行怎么来的?在.C文件里面写上符合C语言部分的源代码.OC也是一样的.记住:OC程序的后缀名是.m. 为什么要链接?第一个.o的目标文件里面它启动不了.因为它没有启动代码我们要加 ...