• 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  

    运行结果:

    优化支持浮点数计算:

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

       

  • 相关阅读:
    HDU 2328 POJ 3450 KMP
    挨踢江湖之十八
    Solr4.2迁移到新项目下异常:java.lang.NoSuchMethodError: org.apache.http.conn.scheme.Scheme.<init>
    滚动条
    《取悦症》听书笔记
    《洞见远胜创意》听书笔记-如何获得洞见
    《乌合之众》听书笔记
    《巨人的工具》听书笔记
    程序员职业生涯规划
    2017第20周摘录
  • 原文地址:https://www.cnblogs.com/wuqianling/p/5671667.html
Copyright © 2020-2023  润新知