import java.util.Arrays;

import java.util.HashMap;

import java.util.Map;

import java.util.Stack;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/**

* 目前只能做简单的四则运算,不支持浮点数和其他符号,不支持多线程

* 计算步骤:

* 1.中辍表达式转后缀

* 2.计算后缀表达式

*/

public class Arithmetic {

/** 错误提示 **/

private static final String ERROR_ZERO = "DividedZero";

/** 检测一个字符串是不是数字 **/

private static Pattern pattern = Pattern.compile("\\d+\\.?\\d?");

/** 运算符优先级 **/

private static Map priority = new HashMap<>();

static {

priority.put("*", 2);

priority.put("/", 2);

priority.put("+", 1);

priority.put("-", 1);

priority.put("", -1); // 无运算符

}

/** 替换表达式中的中文括号 **/

private static Map replace = new HashMap<>();

static {

replace.put("(", "(");

replace.put(")", ")");

}

/** 支持的运算符 **/

private static String[] operator = {"+", "-", "*", "/"};

private static Stack stack = new Stack<>();

/**

* -----------测试代码----------------

*/

public static void main(String[] args) {

String expression = "8+(9-1)*8+7/2";

System.out.println(execute(expression));

}

/**

* 整个计算过程

* @param expression 传入的表达式

* @return 计算结果

*/

public static String execute(String expression) {

return suffixToValue(inffixToSuffix(trim(expression)));

}

/**

* 整理算式,替换掉中文括号等

* @param expression 算式

* @return 整理后的算式

*/

private static String trim(String expression) {

String result = expression.trim();

for (Map.Entry entry : replace.entrySet()) {

result = result.replace(entry.getKey(), entry.getValue());

}

return result;

}

/**

* 将中缀表达式转换成后缀表达式

* eg:中缀表达式8+(9-1)*8+7/2

* 后缀表达式8 9 1 - 8 * + 7 2 / +,元素之间之间用空格分隔。

* 从左到右遍历中缀表达式的每一个数字和运算符

* 如果数字就输出(即存入后缀表达式)

* 如果是右括号,则弹出左括号之前的运算符

* 如果优先级低于栈顶运算符,则弹出栈顶运算符,并将当前运算符进栈

* 遍历结束后,将栈则剩余运算符弹出。

* @param expression 中缀表达式

* @return 后缀表达式

*/

private static String inffixToSuffix(String expression) {

stack.clear();

StringBuilder inffix = new StringBuilder(expression);

StringBuilder suffix = new StringBuilder();

String element = ""; // 中缀表达式的数字或者运算符

String tmp = "";

while (inffix.length() > 0) {

element = popNextElement(inffix);

if (isNum(element)) { // 是数字则输出

suffix.append(element).append(" ");

} else if (")".equals(element)) { // 右括号则将左括号之前的内容全弹出

tmp = stack.pop();

while (!"(".equals(tmp)) {

suffix.append(tmp).append(" ");

tmp = stack.pop();

}

} else if ("(".equals(element) || priority.get(element) >= priority.get(getTopOperator())) {

stack.push(element);

} else { // 优先级小于栈顶运算符,则弹出

tmp = stack.pop();

suffix.append(tmp).append(" ").append(element).append(" ");

}

}

// 把栈中剩余运算符都弹出

while (stack.size() > 0) {

suffix.append(stack.pop()).append(" ");

}

return suffix.toString();

}

/**

* 根据后缀表达式算出结果

* eg:中缀表达式8+(9-1)*8+7/2

* 后缀表达式8 9 1 - 8 * + 7 2 / +,元素之间之间用空格分隔。

* 从左到右遍历后缀表达式

* 遇到数字就进栈

* 遇到符号,就将栈顶的两个数字出栈运算,运算结果进栈,直到获得最终结果。

* -----------目前只支持整数,由于整数相除会出现浮点数,这里用String作为返回值--------

* @param expression 后缀表达式

* @return 结果

*/

private static String suffixToValue(String expression) {

// 已经用空格分隔,直接分割

String[] suffix = expression.split(" ");

stack.clear();

double num1 = 0, num2 = 0; // 注意次序,num2在栈顶,整数运算结果也可能是double

String tmp = "";

for (int i = 0; i < suffix.length; i++) {

if (isNum(suffix[i])) { // 数字

stack.push(suffix[i]);

} else{ // 是操作符

num2 = Double.parseDouble(stack.pop());

num1 = Double.parseDouble(stack.pop());

tmp = calculate(num1, num2, suffix[i]);

if (ERROR_ZERO.equals(tmp)) {

throw new ArithmeticException("被除数不能为0");

} else {

stack.push(tmp);

}

}

}

// 最终结果也压在栈中,取出即可

return stack.pop();

}

/**

* 目前只支持整数,但是整数运算结果也可能是double,故这里传入的参数用double。

* @param num1 第一个数,在前

* @param num2 第二个数,在后

* @param operator 运算符

* @return 运算结果,除数为0则返回Error

*/

private static String calculate(double num1, double num2, String operator) {

double result = 0;

switch (operator) {

case "+":

result = num1 + num2;

break;

case "-":

result = num1 - num2;

break;

case "*":

result = num1 * num2;

break;

case "/":

if (num2 == 0){ // 除数为0

return ERROR_ZERO;

}

result = 1.0 * num1 / num2;

break;

default:

break;

}

return String.valueOf(result);

}

/**

* 检测字符是不是数字

* 浮点数其实可以写零宽断言,但是

* @param c 待检测字符

* @return 检测结果

*/

private static boolean isNum(char c) {

if ( (c >= '0' && c <= '9') || c == '.' ) {

return true;

}

return false;

}

/**

* 检测字符串是不是数字

* @param str 待检测字符串

* @return 检测结果

*/

private static boolean isNum(String str) {

Matcher matcher = pattern.matcher(str);

if (matcher.matches()) {

return true;

}

return false;

}

/**

* 获取栈顶运算符

* @return 如果栈中无运算符,则返回空字符串

*/

private static String getTopOperator() {

String tmp = "";

for (int i = stack.size() - 1; i >= 0; i--) {

tmp = stack.get(i);

if ("(".equals(tmp)) {

break;

} else if (isOperator(tmp)) {

return tmp;

}

}

return "";

}

/**

* 检测一个字符是不是运算符

* 栈中不是运算符就是括号

* @param str 待检测字符,由于可能有多位数字字符串,这里用的是String

* @return 检测结果

*/

private static boolean isOperator(String str) {

for (int i = 0; i < operator.length; i++) {

if (operator[i].equals(str)) {

return true;

}

}

return false;

// // 也可以如下:

// return Arrays.asList(operator).contains(str);

}

/**

* 获取表达式的下一个运算符或数字,同时从表达式中删除该元素

* @param expression 表达式

* @return

*/

private static String popNextElement(StringBuilder expression) {

StringBuilder result = new StringBuilder();

char c = expression.charAt(0);

expression.deleteCharAt(0);

result.append(c);

if (isNum(c)) {

// 如果第一次取到的是数字,则继续检查

while ( expression.length() >0 && isNum(c = expression.charAt(0))) {

expression.deleteCharAt(0);

result.append(c);

}

}

return result.toString();

}

}

java用栈处理四则运算_Java 用栈处理四则运算相关推荐

  1. java栈编程题_Java实现栈和队列面试题

    面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min()的栈,要 ...

  2. java 栈 堆 区别_java中栈与堆的区别

    1. 栈(stack)与堆(heap)都是Java用来在Ram(random access memory随机存取器)中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. ...

  3. java栈与堆_JAVA中的栈和堆

    JAVA在程序运行时,在内存中划分5片空间进行数据的存储.分别是:1:寄存器.2:本地方法区.3:方法区.4:栈.5:堆. 基本,栈stack和堆heap这两个概念很重要,不了解清楚,后面就不用学了. ...

  4. java全栈前景_Java全栈开发哪个发展前景好

    原标题:Java全栈开发哪个发展前景好 全栈和java哪个能更好迎合市场需求,有同学咨询学习哪个在以后前景和工作薪水上能更吃香,首先我们先来了解下Java开发和全栈开发的区别. 全栈开发工程师是指掌握 ...

  5. java中栈和堆都存哪些东西_java中栈内存与堆内存(JVM内存模型)

    java中栈内存与堆内存(JVM内存模型) Java中堆内存和栈内存详解1 和 Java中堆内存和栈内存详解2 都粗略讲解了栈内存和堆内存的区别,以及代码中哪些变量存储在堆中.哪些存储在栈中.内存中的 ...

  6. java什么是栈和堆_JAVA中的栈和堆

    JAVA在程序运行时,在内存中划分5片空间进行数据的存储.分别是:1:寄存器.2:本地方法区.3:方法区.4:栈.5:堆. 基本,栈stack和堆heap这两个概念很重要,不了解清楚,后面就不用学了. ...

  7. java 堆内存和栈内存的区别_java中栈内存和堆内存有什么区别

    栈内存和堆内存的区别: 1.栈内存用来存放基本类型的变量和引用变量,堆内存用来存储java中的对象,无论是成员变量,局部变量,还是类变量,他们指向的对象都存储在堆内存中. (视频教程推荐:java视频 ...

  8. java 栈的变量_Java栈和局部变量操作(一)

    Java栈和局部变量操作 Java虚拟机是基于栈的机器,几乎所有Java虚拟机的指令都与操作数栈相关.栈操作包括把常量压入操作数栈.执行通用的栈操作.在操作数栈和局部变量之间往返传输值. 1常量入栈操 ...

  9. java中的列表栈链表_Java数据结构(栈,队列,双链表)

    (1)栈package ChapterOne; public class Stack { //栈数组 long stackArr[]; //栈的大小 int maxSize; //栈的顶部 int t ...

最新文章

  1. Eclipse-Java代码规范和质量检查插件-阿里编码规约
  2. CentOS6.3挂载读写NTFS分区
  3. Burrard 大桥
  4. 2022年跨境卖家如何布局海外市场?东南亚“钱”景可观
  5. 如何找到cache-control header是从后台何处设置的
  6. springboot/git学习资源记录
  7. Pytorch 其它有关Tensor的话题,GPU,向量化
  8. stl之截取:以一段字符串截取字符串
  9. 独家披露51CTO被黑过程:数据库已小范围流传
  10. MultiByteToWideChar和WideCharToMultiByte的正确使用方法及参数详解
  11. axios post json_助你解析Axios原理之一:如何实现多种请求方式
  12. mysql 账户余额表_账户表/余额表/消费储蓄表
  13. 阿里云 centos 7.6 安装和启动redis 6
  14. 红外遥控器解码串口输出模块结合51单片机+oled屏幕实现遥控器红外解锁( STC89C52RC)
  15. Redis(八):进阶篇 - 事务
  16. effective stl
  17. 微信发红包的测试用例点
  18. heroku常用命令示例(三)与AWS S3互动
  19. 湖北民院OJ 计算球体体积
  20. 量化中获取A股交易日信息

热门文章

  1. Spiral Matrix I II
  2. sql 查看Oralce 数据库连接状态
  3. 流水灯c语言实验报告心得,嵌入式流水灯实验心得体会.docx
  4. apache php的日志在哪里,PHP在哪里存储错误日志? (php5,apache,fastcgi,cpanel)...
  5. 【Pytorch神经网络理论篇】 27 图神经网络DGL库:简介+安装+卸载+数据集+PYG库+NetWorkx库
  6. java jstack 工具_java命令之jstack工具
  7. problem b: 一年中的第几天_第九届蓝桥杯B组试题
  8. 1+X web中级 Laravel学习笔记——blade模版
  9. 使用mongoose 在 Node中操作MongoDB数据库
  10. 使用GRU单元的RNN模型生成唐诗