简单的计算器(java)

今天复习完了数据结构的栈,因此做了一个计算器。但是还有bug我无法解决。(以后学的深了在试试)
此计算器可以实现:小数的加减乘除
未实现:‘(’的左边有运算符且右边有以‘-’开头的表达式,形如:1+(-1)

package stackSet;

import java.util.*;

public class Calculator {
	
	private static Tool<Character> charTool = new Tool<>();
	//操作栈的工具类,此工具类用于操作储存运算符号的栈
	private static Tool<Double> numTool = new Tool<>();
	//操作栈的工具类,此工具类用于操作储存数据的栈
	
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		System.out.println("请输入形如-1+2.2*5+4.1-5+(5+5)/3+(5+5+(1+1))的表达式:");
		String expression = in.nextLine();//获取表达式
		try {
			double result = calculate(expression);//进行计算
			String s = expression + " = " + result;//把结果转换为字符串类型,以便去除小数点后得0
			System.out.println(s);//打印结果
		}catch(Exception e) {
			//System.out.println(e.getMessage());//进行错误提示
			e.printStackTrace();
		}
	}
	public static double calculate(String expression) throws Exception {
		int left = 0;//用于记录左括号的个数
		StackNode<Double> numBase = new StackNode<>();//储存数据的栈
		StackNode<Character> charBase = new StackNode<>();//储存运算符的栈
		
		char[] formula = expression.toCharArray();//把表达式变成字符数组方便操作
		String num = "";//储存数据
		boolean flag = false;//标记位,判断是否有数据被转换
		int pointNum = 0;//判断小数点个数
		int i = 0;//循环次数
		charTool.push('#', charBase);//先将#入栈
		for(;formula[i] == '-' || formula[i] == '+' || formula[i] == '(';) {
			if(formula[i] == '-') {
				num = "-";
				i++; 
			}
			else if(formula[i] == '+') 
				i++;
			else if(formula[i] == '(') {
				charTool.push('(', charBase);
				i++;
				left++;
			}
			if(i >= formula.length) break;
		}
		for(; i < formula.length; i++) {
			//从表达式中取出数据
			for (; (formula[i] >= '0' && formula[i] <= '9') || formula[i] == '.'; ) {
				if(formula[i] == '.') {//判断此数据是否有两个小数点
					if(pointNum == 1) throw new RuntimeException("小数格式不符合规范");
					pointNum++;
				}
				//将数据存入num中
				num = num + formula[i];
				i++;
				flag = true;//将标记位置为真,表示对num进行过操作
				if(i >= formula.length) break;//如果遍历完了整个表达式,则退出
			}
			if(flag) {//如果对数据进行了操作,则将数据转换为double型并入栈
				try {
					double number = Double.parseDouble(num);
					numTool.push(number, numBase);
				}catch(Exception e) {
					throw new RuntimeException("小数不规范!!!");
				}
			}
			flag = false;//重置标记位
			if(i >= formula.length) break;//如果遍历完了整个表达式,则退出
			if(formula[i] == '(') {//如果是左括号,则入栈
				charTool.push('(', charBase);
				left++;
			}
			else if (formula[i] == ')') {//如果是右括号,则对栈进行操作
				left--;
				double result = isMatch(charBase, numBase);
				//ismatch的返回值是小括号内的表达式的值
				numTool.push(result, numBase);//将此值入栈
			}
			else {
				compare(formula[i], charBase, numBase);//如果是+,-,*,/,#则判断优先级
			}
			num = "";
			pointNum = 0;
		}
		compare('#', charBase, numBase);//#的优先级最低,所以最后将其入栈
		if(left != 0) throw new RuntimeException("括号不匹配,无法计算!");
		//每操作一个')'就会使left--,如果left最后的值大于0或者小于0,则会抛出异常
		return numTool.pop(numBase);//将结果返回
	}
	public static void compare(char ch1,StackNode<Character> charBase, 
			StackNode<Double> numBase) {
		char ch3 = '\0'; 
		char ch2 = charTool.pop(charBase);//取出上一个运算符
		if( !charTool.isEmpty(charBase)) {
			ch3 = charTool.pop(charBase);
			charTool.push(ch3, charBase);//再把它塞回去	
		}
		charTool.push(ch2, charBase);
		if(ch3 == '(') {
			charTool.push(ch1, charBase);
			return;
		}
		switch(ch1) {//判断ch1是什么符号
		case '+': if(ch2 == '-' || ch2 == '*' || ch2 == '/') {
			//如果是+号,且前面是-,/,*,则对前面的数字进行运算 
						merge(charBase, numBase);//运算前面的数字
						compare(ch1, charBase, numBase);//再次进行比较
				  }else charTool.push(ch1, charBase);break;//如果优先级比前面的高,就直接入栈
		case '-': if(ch2 == '*' || ch2 == '/') {
						merge(charBase, numBase); 
						compare(ch1, charBase, numBase);
				  } 
				  else charTool.push(ch1, charBase);break;
		case '*':
		case '/': charTool.push(ch1, charBase);break;
		case '#': if(ch2 != '#') {//#优先级最低,所以直到碰到栈底的#她会一直对栈里的数字进行运算
						merge(charBase, numBase); 
						compare(ch1, charBase, numBase);
					}break;
		default:break;
		}
	}
	public static void merge(StackNode<Character> charBase, StackNode<Double> numBase) {
		if(numTool.isEmpty(numBase))//如果是空栈,则抛异常
			throw new RuntimeException("表达式不规范!");
		double b = numTool.pop(numBase);
		if(numTool.isEmpty(numBase))
			throw new RuntimeException("表达式不规范!");
		double a = numTool.pop(numBase);
		char ch = charTool.pop(charBase);
		//对数据进行运算
		switch(ch) {
			case '+': numTool.push(a + b, numBase);break;
			case '-': numTool.push(a - b, numBase);break;
			case '*': numTool.push(a * b, numBase);break;
			case '/': numTool.push(a / b, numBase);break;
		}
	}
	public static double isMatch(StackNode<Character> charBase, StackNode<Double> numBase) throws Exception{
		String operator = "";//用来储存运算符的字符串
		char ch = '\0';
		//对运算符栈进行出栈操作,直到弹出了'('或者栈为空
		while((ch = charTool.pop(charBase)) != '(' && !charTool.isEmpty(charBase))
			operator += ch;
		if(charTool.isEmpty(charBase)) //如果栈中元素全部弹出还是没找到'(',则抛异常
			throw new RuntimeException("括号不匹配,无法计算!");
		double[] number = new double[operator.length() + 1];//将数据也弹出
		try {
			for(int i = 0; i < operator.length() + 1; i++) {
				number[i] = numTool.pop(numBase);
			}
		}catch(Exception e) {
			throw new RuntimeException("表达式不规范");
		}
		char[] ope = operator.toCharArray();//把字符串转化为字符数组,方便操作
		String expression = "";
		//将括号内的表达式重新整合
		if(operator.equals("")) {
			expression += number[0];
		}
		else {
			for(int i = number.length - 1; i > 0 ; i--) {
				expression = expression + number[i] + ope[i - 1];
			}
			expression += number[0];	
		}
		double result = calculate(expression);//求出括号内的表达式的值
		return result;
	}
}

class Tool<T>{
	public void cleanStack(StackNode<T> base) {
		base.setNext(null);
	}
	public boolean isEmpty(StackNode<T> base) {
		if(base.getNext() != null) return false;
		return true;
	}
	public void push(T x, StackNode<T> base) {
		StackNode<T> temp = new StackNode<>(x);
		temp.setNext(base.getNext());
		base.setNext(temp);
	}
   	 public T pop(StackNode<T> base) {
    		if(base.getNext() == null) return null;
    		T num = (T) base.getNext().getData();
    		base.setNext(base.getNext().getNext());
    		return num;
    	}
   	 public void travel(StackNode<T> base) {
    		base = base.getNext();
    		while(base != null) {
        		System.out.print(base.getData().toString() + "    ");
        		base = base.getNext();
    	}
    }
}
class StackNode<T>{
	private T data = null;
	private StackNode<T> next = null;
	public StackNode(){}
	public StackNode(T data){
		this.data = data;
	}
	public void setData(T data) {
		this.data = data;
	}
	public T getData() {
		return data;
	}
	public void setNext(StackNode<T> next) {
		this.next = (StackNode<T>) next;
	}
	public StackNode<T> getNext() {
		return next;
	}
}
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页