java用栈处理四则运算_Java 用栈处理四则运算

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();

}

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/475902.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 846. 一手顺子(map)

1. 题目 爱丽丝有一手&#xff08;hand&#xff09;由整数数组给定的牌。 现在她想把牌重新排列成组&#xff0c;使得每个组的大小都是 W&#xff0c;且由 W 张连续的牌组成。 如果她可以完成分组就返回 true&#xff0c;否则返回 false。 示例 1&#xff1a; 输入&#xf…

25 To Life

《25 To Life 》 too late for the other side 现在回头为时已晚 caught in a change 由于一次变故 25 to life 25岁时,即决定了一生 too late for the other side 现在回头为时已晚 caught in a change 由于一次变故 25 to life 25岁时,即决定了一生 …

多线程 流水线 java_Java Lock锁多线程中实现流水线任务

下面程序代码通过使用Lock锁执行简单的流水线任务&#xff1a;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*** author lzq* data 2020/4/29 0029 - 下午 9:48*/public class Test…

LeetCode 962. 最大宽度坡(单调栈)

1. 题目 给定一个整数数组 A&#xff0c;坡是元组 (i, j)&#xff0c;其中 i < j 且 A[i] < A[j]。这样的坡的宽度为 j - i。 找出 A 中的坡的最大宽度&#xff0c;如果不存在&#xff0c;返回 0 。 示例 1&#xff1a; 输入&#xff1a;[6,0,8,2,1,5] 输出&#xff1…

java 加载资源文件

ClassLoader提供了两个方法用于从装载的类路径中取得资源&#xff1a; public URL getResource(String name); public InputStream getResourceAsStream(String name);这里name是资源的类路径&#xff0c;它是相对与“/”根路径下的位置。getResource得到的是一个URL对象来定位…

Java用链表写图书管理_C语言链表实现图书管理系统

之前参照网上的资料用链表实现了图书管理系统&#xff0c;包括简单的增删改查功能以及借书还书功能&#xff0c;我是VC6.0下写的一个控制台程序&#xff0c;格式参照的网上的。在动手编码之前&#xff0c;你需要理清自己的思路。首先&#xff0c;需要确定图书馆里系统中主要有那…

【Kaggle】Intermediate Machine Learning(缺失值+文字特征处理)

文章目录1. Introduction2. Missing Values 缺失值处理3. Categorical Variables 文字变量处理from https://www.kaggle.com/learn/intermediate-machine-learning下一篇 &#xff1a;【Kaggle】Intermediate Machine Learning&#xff08;管道交叉验证&#xff09; 1. Intro…

VB6调用API打开目标文件所在文件夹且选中目标文件

Option Explicit 模块名称: mOpenFolderAndSetFileFocus 作者: 唐细刚 时间: 2010-08-22 功能: VB6调用API打开目标文件所在文件夹且选中目标文件 注&#xff1a; 由于调用 Explorer.exe /select 方式会使系统产生多余的 Explorer.exe 进程 所以还是API来实现较好…

python 保存文件 吃内存_孤荷凌寒自学python第三十七天python的文件与内存变量之间的序列化与反序列化...

孤荷凌寒自学python第三十七天python的文件与内存变量之间的序列化与反序列化(完整学习过程屏幕记录视频地址在文末&#xff0c;手写笔记在文末)一、什么是序列化与反序列化序列化是指将内存中的数据进行指定规则的格式梳理&#xff0c;使之方便按一定格式保存到文件中。我的理…

【Kaggle】Intermediate Machine Learning(管道+交叉验证)

文章目录4. Pipelines 管道5. Cross-Validation 交叉验证上一篇&#xff1a;【Kaggle】Intermediate Machine Learning&#xff08;缺失值文字特征处理&#xff09; 下一篇&#xff1a;【Kaggle】Intermediate Machine Learning&#xff08;XGBoost Data Leakage&#xff09; …

ASP.NET2.0导出Word文档(C#导出DOC)

在网络上看到很多关于ASP.NET导出DOC文档的例子&#xff0c;有的干脆就直接将html页面不做任何处理直接导出为DOC文件&#xff0c;但是那样会有很多错误&#xff0c;例如将某些控件显示为图片。我还曾经见过微软为中国某个大公司制作的一个XX系统&#xff0c;导出的DOC文件实际…

java todo error_java.sql.SQLException: sql injection violation, syntax error: TODO UNIQUE unique

wenshao 你好&#xff0c;想跟你请教个问题&#xff1a;我是在用activiti工作流的时候 初始化生成流程表产生了下面的问题工作流引擎代码&#xff1a;ProcessEngineConfiguration config ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();config.se…

ASP VBScript 函数速查表

VBScript函数 功能说明 例子 Abs &#xff08;数值&#xff09;绝对值。一个数字的绝对值是它的正值。空字符串 (null) 的绝对值&#xff0c;也是空字符串。未初始化的变数&#xff0c;其绝对为 0例子&#xff1a;ABS(-2000) 结果&#xff1a;2000Array &#xff08;以逗点分…

LeetCode 201. 数字范围按位与(位运算)

文章目录1. 题目2. 解题2.1 按位查找02.2 两数直接都往右移动&#xff0c;直到相等1. 题目 给定范围 [m, n]&#xff0c;其中 0 < m < n < 2147483647&#xff0c;返回此范围内所有数字的按位与&#xff08;包含 m, n 两端点&#xff09;。 示例 1: 输入: [5,7] 输…

编php矩阵求和,PHP二维数组如何求和?

PHP二维数组求和的方法&#xff1a;1、使用array_sum和array_map函数求和1)、PHP7.2以下可用<?php $arr array(0>array(id>1,tol>10),1>array(id>3,tol>12),2>array(id>8,tol>5));//输出tol值的和echo array_sum(array_map(create_function($v…

LeetCode 1311. 获取你好友已观看的视频(BFS+哈希map+vector排序)

1. 题目 有 n 个人&#xff0c;每个人都有一个 0 到 n-1 的唯一 id 。 给你数组 watchedVideos 和 friends &#xff0c;其中 watchedVideos[i] 和 friends[i] 分别表示 id i 的人观看过的视频列表和他的好友列表。 Level 1 的视频包含所有你好友观看过的视频&#xff0c; …

发布ASP.NET程序至IIS7

以前一直和IIS5打交道&#xff0c;后来系统升级到WIN7,自然的就用上了IIS7了&#xff0c;不过因为对IIS7服务器没有系统的了解&#xff0c;所以在自己机子上测试发布网站时&#xff0c;总是遇到各种各样的问题&#xff0c;当时就放弃了&#xff0c;准备有时间再研究的&#xff…

php请求来源,php验证请求页面来源

php教程验证请求页面来源if( $_server[http_x_requested_with] xmlhttprequest ) {echo ajax;} else {echo normal;}jquery内部实现ajax的时候&#xff0c;已经加入了标识jquery源码中是这样的&#xff1a;xhr.setrequestheader("x-requested-with", "xmlhttpr…

LeetCode 1319. 连通网络的操作次数(BFS/DFS/并查集)

文章目录1. 题目2. 解题2.1 BFS2.2 DFS2.3 并查集1. 题目 用以太网线缆将 n 台计算机连接成一个网络&#xff0c;计算机的编号从 0 到 n-1。 线缆用 connections 表示&#xff0c;其中 connections[i] [a, b] 连接了计算机 a 和 b。 网络中的任何一台计算机都可以通过网络直…

1D機身調焦方法

原文作者&#xff1a;Kent 原文地址&#xff1a;http://www.ldsclub.net/forum/viewthread.php?tid21513&extrapage%3D1&page1另附大兔子調焦心得&#xff1a;http://www.ldsclub.net/forum/viewthread.php?tid28268&extrapage%3D1 需要1.27規格的6角手柄本次轉文…