这个计算器不仅能够进行四则运算,还支持添加括号进行优先级计算,例如下面算式:

10+(2*16-20/5)+7*2=52

Java源代码:

 import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Stack; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField; /**
* 计算器
*/
public class Calculator { /** 数字栈:用于存储表达式中的各个数字 */
private Stack<Long> numberStack = null;
/** 符号栈:用于存储运算符和括号 */
private Stack<Character> symbolStack = null; /**
* 解析并计算四则运算表达式(含括号),返回计算结果
*
* @param numStr
* 算术表达式(含括号)
*/
public long caculate(String numStr) {
numStr = removeStrSpace(numStr); // 去除空格
// 如果算术表达式尾部没有‘=’号,则在尾部添加‘=’,表示结束符
if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
numStr += "=";
}
// 检查表达式是否合法
if (!isStandard(numStr)) {
System.err.println("错误:算术表达式有误!");
return 0;
}
// 初始化栈
numberStack = new Stack<Long>();
symbolStack = new Stack<Character>();
// 用于缓存数字,因为数字可能是多位的
StringBuffer temp = new StringBuffer();
// 从表达式的第一个字符开始处理
for (int i = 0; i < numStr.length(); i++) {
char ch = numStr.charAt(i); // 获取一个字符
if (isNumber(ch)) { // 若当前字符是数字
temp.append(ch); // 加入到数字缓存中
} else { // 非数字的情况
String tempStr = temp.toString(); // 将数字缓存转为字符串
if (!tempStr.isEmpty()) {
long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
numberStack.push(num); // 将数字压栈
temp = new StringBuffer(); // 重置数字缓存
}
// 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
while (!comparePri(ch) && !symbolStack.empty()) {
long b = numberStack.pop(); // 出栈,取出数字,后进先出
long a = numberStack.pop();
// 取出运算符进行相应运算,并把结果压栈进行下一次运算
switch ((char) symbolStack.pop()) {
case '+':
numberStack.push(a + b);
break;
case '-':
numberStack.push(a - b);
break;
case '*':
numberStack.push(a * b);
break;
case '/':
numberStack.push(a / b);
break;
default:
break;
}
} // while循环结束
if (ch != '=') {
symbolStack.push(new Character(ch)); // 符号入栈
if (ch == ')') { // 去括号
symbolStack.pop();
symbolStack.pop();
}
}
}
} // for循环结束 return numberStack.pop(); // 返回计算结果
} /**
* 去除字符串中的所有空格
*/
private String removeStrSpace(String str) {
return str != null ? str.replaceAll(" ", "") : "";
} /**
* 检查算术表达式的基本合法性,符合返回true,否则false
*/
private boolean isStandard(String numStr) {
if (numStr == null || numStr.isEmpty()) // 表达式不能为空
return false;
Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
boolean b = false; // 用来标记'='符号是否存在多个
for (int i = 0; i < numStr.length(); i++) {
char n = numStr.charAt(i);
// 判断字符是否合法
if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
|| "+".equals(n + "") || "-".equals(n + "")
|| "*".equals(n + "") || "/".equals(n + "")
|| "=".equals(n + ""))) {
return false;
}
// 将左括号压栈,用来给后面的右括号进行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括号
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
return false;
}
// 检查是否有多个'='号
if ("=".equals(n + "")) {
if (b)
return false;
b = true;
}
}
// 可能会有缺少右括号的情况
if (!stack.isEmpty())
return false;
// 检查'='号是否不在末尾
if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
return false;
return true;
} /**
* 判断字符是否是0-9的数字
*/
private boolean isNumber(char num) {
if (num >= '0' && num <= '9')
return true;
return false;
} /**
* 比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
*/
private boolean comparePri(char symbol) {
if (symbolStack.empty()) { // 空栈返回ture
return true;
} // 符号优先级说明(从高到低):
// 第1级: (
// 第2级: * /
// 第3级: + -
// 第4级: ) char top = (char) symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
if (top == '(') {
return true;
}
// 比较优先级
switch (symbol) {
case '(': // 优先级最高
return true;
case '*': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '/': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 优先级最低
return false;
case '=': // 结束符
return false;
default:
break;
}
return true;
} // 测试
public static void main(String args[]) {
String num = "10 + (2*16-20/5) + 7*2 "; // 默认的算式
// 创建一个窗口
JFrame win = new JFrame("计算器");
Container con = win.getContentPane();
JPanel pa = new JPanel();
pa.add(new JLabel("输入算式:")); // 添加一个标签
final JTextField formulaText = new JTextField(num, 20); // 算式输入框
pa.add(formulaText);
pa.add(new JLabel("="));
final JTextField resultText = new JTextField(8); // 结果文本框
pa.add(resultText);
con.add(pa); JButton bn = new JButton("计算"); // 实例化按钮对象
con.add(bn, BorderLayout.EAST); // 将按钮添加到右边
win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭窗口退出程序
win.pack(); // 自动调整大小
win.setLocationRelativeTo(null); // 设置窗口居中于屏幕
win.setVisible(true); // 显示窗口 // 添加按钮点击事件
bn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) { // 每当按钮点击时调用该方法
/* 计算器操作 */
Calculator cal = new Calculator();
String numStr = formulaText.getText(); // 获得算式文本框中的文字
long result = cal.caculate(numStr); // 计算算式的结果
numStr = cal.removeStrSpace(numStr); // 去空格
formulaText.setText(numStr); // 将去空格的算式放回算式文本框中
resultText.setText(result + ""); // 在结果文本框中显示结果
}
});
}
}

运行结果:

优化支持浮点数计算:

import java.math.BigDecimal;
import java.util.Stack; /**
* 算式计算
*/
public class FormulaUtil { private int scale; // 进行除法出现无线循环小数时保留的精度 /** 数字栈:用于存储表达式中的各个数字 */
private Stack<BigDecimal> numberStack = null;
/** 符号栈:用于存储运算符和括号 */
private Stack<Character> symbolStack = null; public FormulaUtil(int scale) {
super();
this.scale = scale;
} public FormulaUtil() {
this(32);
} /**
* 解析并计算四则运算表达式(含括号优先级),返回计算结果
*
* @param numStr
* 算术表达式(含括号)
*/
public BigDecimal caculate(String numStr) {
numStr = removeStrSpace(numStr); // 去除空格
// 如果算术表达式尾部没有‘=’号,则在尾部添加‘=’,表示结束符
if (numStr.length() > 1
&& !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
numStr += "=";
}
// 检查表达式是否合法
if (!isStandard(numStr)) {
System.err.println("错误:算术表达式有误!");
return null;
}
// 初始化栈
if (numberStack == null) {
numberStack = new Stack<BigDecimal>();
}
numberStack.clear();
if (symbolStack == null) {
symbolStack = new Stack<Character>();
}
symbolStack.clear();
// 用于缓存数字,因为数字可能是多位的
StringBuffer temp = new StringBuffer();
// 从表达式的第一个字符开始处理
for (int i = 0; i < numStr.length(); i++) {
char ch = numStr.charAt(i); // 获取一个字符
if (isNumber(ch)) { // 若当前字符是数字
temp.append(ch); // 加入到数字缓存中
} else { // 非数字的情况
String tempStr = temp.toString(); // 将数字缓存转为字符串
if (!tempStr.isEmpty()) {
// long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
BigDecimal num = new BigDecimal(tempStr);
numberStack.push(num); // 将数字压栈
temp = new StringBuffer(); // 重置数字缓存
}
// 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
while (!comparePri(ch) && !symbolStack.empty()) {
BigDecimal b = numberStack.pop(); // 出栈,取出数字,后进先出
BigDecimal a = numberStack.pop();
// 取出运算符进行相应运算,并把结果压栈进行下一次运算
switch ((char) symbolStack.pop()) {
case '+':
numberStack.push(a.add(b));
break;
case '-':
numberStack.push(a.subtract(b));
break;
case '*':
numberStack.push(a.multiply(b));
break;
case '/':
try {
numberStack.push(a.divide(b));
} catch (java.lang.ArithmeticException e) {
// 进行除法出现无限循环小数时,就会抛异常,此处设置精度重新计算
numberStack.push(a.divide(b, this.scale,
BigDecimal.ROUND_HALF_EVEN));
}
break;
default:
break;
}
} // while循环结束
if (ch != '=') {
symbolStack.push(new Character(ch)); // 符号入栈
if (ch == ')') { // 去括号
symbolStack.pop();
symbolStack.pop();
}
}
}
} // for循环结束 return numberStack.pop(); // 返回计算结果
} /**
* 去除字符串中的所有空格
*/
private String removeStrSpace(String str) {
return str != null ? str.replaceAll(" ", "") : "";
} /**
* 检查算术表达式的基本合法性,符合返回true,否则false
*/
private boolean isStandard(String numStr) {
if (numStr == null || numStr.isEmpty()) // 表达式不能为空
return false;
Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
boolean b = false; // 用来标记'='符号是否存在多个
for (int i = 0; i < numStr.length(); i++) {
char n = numStr.charAt(i);
// 判断字符是否合法
if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
|| "+".equals(n + "") || "-".equals(n + "")
|| "*".equals(n + "") || "/".equals(n + "") || "=".equals(n
+ ""))) {
return false;
}
// 将左括号压栈,用来给后面的右括号进行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括号
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
return false;
}
// 检查是否有多个'='号
if ("=".equals(n + "")) {
if (b)
return false;
b = true;
}
}
// 可能会有缺少右括号的情况
if (!stack.isEmpty())
return false;
// 检查'='号是否不在末尾
if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
return false;
return true;
} /**
* 判断字符是否是0-9的数字
*/
private boolean isNumber(char num) {
if ((num >= '0' && num <= '9') || num == '.')
return true;
return false;
} /**
* 比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
*/
private boolean comparePri(char symbol) {
if (symbolStack.empty()) { // 空栈返回ture
return true;
} // 符号优先级说明(从高到低):
// 第1级: (
// 第2级: * /
// 第3级: + -
// 第4级: ) char top = (char) symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
if (top == '(') {
return true;
}
// 比较优先级
switch (symbol) {
case '(': // 优先级最高
return true;
case '*': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '/': {
if (top == '+' || top == '-') // 优先级比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 优先级最低
return false;
case '=': // 结束符
return false;
default:
break;
}
return true;
} // 测试
public static void main(String args[]) {
String numStr = "10.000000000000000009 + (2*16-20/4) + 7*2.5 "; // 默认的算式
BigDecimal result = new FormulaUtil().caculate(numStr); // 计算算式的结果
System.out.println(numStr + "=");
System.out.println(result);
}
}

  

Java实现带括号优先级的计算器的更多相关文章

  1. java实现可有括号的android计算器

    写了一个android版的计算器,可以计算带括号的表达式,不过前提是:正确的表达式才行 小缺陷是没有做表达式括号的控制,现在还没有想到好的控制方式 package javaAdvanced; impo ...

  2. Python带括号的计算器

    带括号的计算器也是第一个自我感觉完成最好的 毕竟真的弄了一个多星期 虽然前期这路真的很难走  我会努力加油  将Python学好学踏实 参考了两位博主的文章 http://www.cnblogs.co ...

  3. 使用python开发一个能够计算带括号的复杂表达式的计算器(只支持加减乘除)

    使用到了模块re,正则,字典等 # 实现简单的加减乘除括号等运算 # Calculator def calculator(expression): print(expression) import r ...

  4. java中运算符的优先级

    所谓优先级,就是在表达式中的运算顺序.Java 中常用的运算符的优先级如下表所示: 级别为 1 的优先级最高,级别 11 的优先级最低.譬如,x = 7 + 3 * 2  得到的结果是 13 &quo ...

  5. 慕课网-安卓工程师初养成-3-9 Java中运算符的优先级

    来源 http://www.imooc.com/code/1315 所谓优先级,就是在表达式中的运算顺序.Java 中常用的运算符的优先级如下表所示: 级别为 1 的优先级最高,级别 11 的优先级最 ...

  6. (转载)Java自带的GUI性能监控工具Jconsole以及JisualVM简介

    原文链接:http://blog.csdn.net/chendc201/article/details/22905503 1 Jconsole 1.1 简介以及连接 JConsole是一个基于JMX的 ...

  7. Java课程设计----仿Windows标准型计算器

    JAVA课程设计 仿Windows标准型计算器(By Yanboooooooo) 一.团队介绍: 连燕波[组长]:网络1513学生. 张文博[组员]:网络1513学生. 二.项目git地址 码云项目地 ...

  8. js中new函数后带括号和不带括号的区别

    用new创建构造函数的实例时,通常情况下new 的构造函数后面需要带括号(譬如:new Parent()). 有些情况下new的构造函数后带括号和不带括号的情况一致,譬如: function Pare ...

  9. 解决VS Code开发Python3语言自动补全功能不带括号的问题

    Visual Studio Code(以下简称VS Code)用来开发Python3,还是很便利的,本身这个IDE就是轻量级的,才几十兆大小,通过安装插件的方式支持各种语言的开发.界面也美美哒,可以在 ...

随机推荐

  1. java常量池存放在哪里

    运行以下方法: public class Test { public static void main(String[] args) { String str = "abc"; c ...

  2. PHP Socket实现websocket(二)Socket函数

    PHP socket函数是调用系统的的Socket函数,可以参考C语言的socket函数. Socket函数:http://php.net/manual/en/book.sockets.php 服务器 ...

  3. 原生态js,鼠标按下后,经过了那些单元格

    本来是要判断那些单元格被选中,结果发现行不通,只能判断鼠标按下后,经过了那些单元格 之所以发出来,是觉得案例还有很多有意思的地方 onmouseover  的持续触发,导致了很多重复元素 由于将事件绑 ...

  4. ProgressDialog使用总结

    以前对ProgressDialog不太熟练,特地看到的这个文章 ProgressDialog的使用  ProgressDialog 继承自AlertDialog,AlertDialog继承自Dialo ...

  5. BZOJ1012——[JSOI2008]最大数maxnumber

    1.题目大意:求末尾L个数的最大值,强制在线 2.分析:这个拿线段树可以直接水过,然后我写了一个 维护单调栈, 二分求最大值的短代码,手懒.... #include <cstdio> #i ...

  6. API23时权限不被许可

    In Android 6.0 Marshmallow, application will not be granted any permission at installation time. Ins ...

  7. opencv图像操作

      cvAbs 计算数组中所有元素的绝对值 cvAbsDiff 计算两个数组差值的绝对值 cvAbsDiffs 计算数组和标量差值的绝对值 cvAdd 两个数组的元素级的加运算 cvAdds 一个数组 ...

  8. 《oracle每日一练》oracle截取字符的函数

    转载 在Oracle中 可以使用instr函数对某个字符串进行判断,判断其是否含有指定的字符. 在一个字符串中查找指定的字符,返回被查找到的指定的字符的位置. 语法: instr(sourceStri ...

  9. Sum of Left Leaves

    Find the sum of all left leaves in a given binary tree. Example: 3 / \ 9 20 / \ 15 7 There are two l ...

  10. Binary Tree Upside Down

    Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that ...