Java实现带括号优先级的计算器

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

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

 

Java源代码:

  1 import java.awt.BorderLayout;
  2 import java.awt.Container;
  3 import java.awt.event.ActionEvent;
  4 import java.awt.event.ActionListener;
  5 import java.util.Stack;
  6 
  7 import javax.swing.JButton;
  8 import javax.swing.JFrame;
  9 import javax.swing.JLabel;
 10 import javax.swing.JPanel;
 11 import javax.swing.JTextField;
 12 
 13 /**
 14  * 计算器
 15  */
 16 public class Calculator {
 17 
 18     /** 数字栈:用于存储表达式中的各个数字 */
 19     private Stack<Long> numberStack = null;
 20     /** 符号栈:用于存储运算符和括号 */
 21     private Stack<Character> symbolStack = null;
 22 
 23     /**
 24      * 解析并计算四则运算表达式(含括号),返回计算结果
 25      * 
 26      * @param numStr
 27      *            算术表达式(含括号)
 28      */
 29     public long caculate(String numStr) {
 30         numStr = removeStrSpace(numStr); // 去除空格
 31         // 如果算术表达式尾部没有‘=’号,则在尾部添加‘=’,表示结束符
 32         if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
 33             numStr += "=";
 34         }
 35         // 检查表达式是否合法
 36         if (!isStandard(numStr)) {
 37             System.err.println("错误:算术表达式有误!");
 38             return 0;
 39         }
 40         // 初始化栈
 41         numberStack = new Stack<Long>();
 42         symbolStack = new Stack<Character>();
 43         // 用于缓存数字,因为数字可能是多位的
 44         StringBuffer temp = new StringBuffer();
 45         // 从表达式的第一个字符开始处理
 46         for (int i = 0; i < numStr.length(); i++) {
 47             char ch = numStr.charAt(i); // 获取一个字符
 48             if (isNumber(ch)) { // 若当前字符是数字
 49                 temp.append(ch); // 加入到数字缓存中
 50             } else { // 非数字的情况
 51                 String tempStr = temp.toString(); // 将数字缓存转为字符串
 52                 if (!tempStr.isEmpty()) {
 53                     long num = Long.parseLong(tempStr); // 将数字字符串转为长整型数
 54                     numberStack.push(num); // 将数字压栈
 55                     temp = new StringBuffer(); // 重置数字缓存
 56                 }
 57                 // 判断运算符的优先级,若当前优先级低于栈顶的优先级,则先把计算前面计算出来
 58                 while (!comparePri(ch) && !symbolStack.empty()) {
 59                     long b = numberStack.pop(); // 出栈,取出数字,后进先出
 60                     long a = numberStack.pop();
 61                     // 取出运算符进行相应运算,并把结果压栈进行下一次运算
 62                     switch ((char) symbolStack.pop()) {
 63                     case '+':
 64                         numberStack.push(a + b);
 65                         break;
 66                     case '-':
 67                         numberStack.push(a - b);
 68                         break;
 69                     case '*':
 70                         numberStack.push(a * b);
 71                         break;
 72                     case '/':
 73                         numberStack.push(a / b);
 74                         break;
 75                     default:
 76                         break;
 77                     }
 78                 } // while循环结束
 79                 if (ch != '=') {
 80                     symbolStack.push(new Character(ch)); // 符号入栈
 81                     if (ch == ')') { // 去括号
 82                         symbolStack.pop();
 83                         symbolStack.pop();
 84                     }
 85                 }
 86             }
 87         } // for循环结束
 88 
 89         return numberStack.pop(); // 返回计算结果
 90     }
 91 
 92     /**
 93      * 去除字符串中的所有空格
 94      */
 95     private String removeStrSpace(String str) {
 96         return str != null ? str.replaceAll(" ", "") : "";
 97     }
 98 
 99     /**
100      * 检查算术表达式的基本合法性,符合返回true,否则false
101      */
102     private boolean isStandard(String numStr) {
103         if (numStr == null || numStr.isEmpty()) // 表达式不能为空
104             return false;
105         Stack<Character> stack = new Stack<Character>(); // 用来保存括号,检查左右括号是否匹配
106         boolean b = false; // 用来标记'='符号是否存在多个
107         for (int i = 0; i < numStr.length(); i++) {
108             char n = numStr.charAt(i);
109             // 判断字符是否合法
110             if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
111                     || "+".equals(n + "") || "-".equals(n + "")
112                     || "*".equals(n + "") || "/".equals(n + "")
113                     || "=".equals(n + ""))) {
114                 return false;
115             }
116             // 将左括号压栈,用来给后面的右括号进行匹配
117             if ("(".equals(n + "")) {
118                 stack.push(n);
119             }
120             if (")".equals(n + "")) { // 匹配括号
121                 if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括号是否匹配
122                     return false;
123             }
124             // 检查是否有多个'='号
125             if ("=".equals(n + "")) {
126                 if (b)
127                     return false;
128                 b = true;
129             }
130         }
131         // 可能会有缺少右括号的情况
132         if (!stack.isEmpty())
133             return false;
134         // 检查'='号是否不在末尾
135         if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
136             return false;
137         return true;
138     }
139 
140     /**
141      * 判断字符是否是0-9的数字
142      */
143     private boolean isNumber(char num) {
144         if (num >= '0' && num <= '9')
145             return true;
146         return false;
147     }
148 
149     /**
150      * 比较优先级:如果当前运算符比栈顶元素运算符优先级高则返回true,否则返回false
151      */
152     private boolean comparePri(char symbol) {
153         if (symbolStack.empty()) { // 空栈返回ture
154             return true;
155         }
156 
157         // 符号优先级说明(从高到低):
158         // 第1级: (
159         // 第2级: * /
160         // 第3级: + -
161         // 第4级: )
162 
163         char top = (char) symbolStack.peek(); // 查看堆栈顶部的对象,注意不是出栈
164         if (top == '(') {
165             return true;
166         }
167         // 比较优先级
168         switch (symbol) { 
169         case '(': // 优先级最高
170             return true;
171         case '*': {
172             if (top == '+' || top == '-') // 优先级比+和-高
173                 return true;
174             else
175                 return false;
176         }
177         case '/': {
178             if (top == '+' || top == '-') // 优先级比+和-高
179                 return true;
180             else
181                 return false;
182         }
183         case '+':
184             return false;
185         case '-':
186             return false;
187         case ')': // 优先级最低
188             return false;
189         case '=': // 结束符
190             return false;
191         default:
192             break;
193         }
194         return true;
195     }
196 
197     // 测试
198     public static void main(String args[]) {
199         String num = "10 + (2*16-20/5) + 7*2 "; // 默认的算式
200         // 创建一个窗口
201         JFrame win = new JFrame("计算器");
202         Container con = win.getContentPane();
203         JPanel pa = new JPanel();
204         pa.add(new JLabel("输入算式:")); // 添加一个标签
205         final JTextField formulaText = new JTextField(num, 20); // 算式输入框
206         pa.add(formulaText);
207         pa.add(new JLabel("="));
208         final JTextField resultText = new JTextField(8); // 结果文本框
209         pa.add(resultText);
210         con.add(pa);
211 
212         JButton bn = new JButton("计算"); // 实例化按钮对象
213         con.add(bn, BorderLayout.EAST); // 将按钮添加到右边
214         win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置关闭窗口退出程序
215         win.pack(); // 自动调整大小
216         win.setLocationRelativeTo(null); // 设置窗口居中于屏幕
217         win.setVisible(true); // 显示窗口
218 
219         // 添加按钮点击事件
220         bn.addActionListener(new ActionListener() {
221             @Override
222             public void actionPerformed(ActionEvent e) { // 每当按钮点击时调用该方法
223                 /* 计算器操作 */
224                 Calculator cal = new Calculator();
225                 String numStr = formulaText.getText(); // 获得算式文本框中的文字
226                 long result = cal.caculate(numStr); // 计算算式的结果
227                 numStr = cal.removeStrSpace(numStr); // 去空格
228                 formulaText.setText(numStr); // 将去空格的算式放回算式文本框中
229                 resultText.setText(result + ""); // 在结果文本框中显示结果
230             }
231         });
232     }
233 }
234  

 

运行结果:

 

转载于:https://www.cnblogs.com/wuqianling/p/5671667.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值