计算器【Java算法(六)】

写在前面的话:

  1. 本次参考资料:如何用C语言编写一个计算器(川川菜鸟)
  2. 所需知识点:了解栈的基本原理,出栈与入栈
  3. IDE:IntelliJ IDEA 2021.2.1
  4. JDK:Java8

目录

1.计算器类

 2.测试计算器

3.运行截图


项目结构:

 

本次代码if-else语句较多,请耐心观看。

遍历整个计算式时,笔者将其分为3个部分:

  1. 遍历的位置含有减号-
  2. 遍历的位置含有左括号()和减号-
  3. 遍历的位置是数字
  4. 遍历的位置是操作符

1.计算器类

Calculator.java
package com.application;

/*
    栈的实际应用:计算器
 */

public class Calculator {

    private String calculate;//输入的计算式子 ==> 字符串形式

    private double[] operand;//放操作数的栈,double ==> 该计算器支持浮点数运算
    private int operandTop;//操作数的栈顶

    private char[] operator;//放操作符的栈
    private int operatorTop;//操作符的栈顶

    public Calculator(){
        //初始化栈空间
        operand = new double[10];
        operator = new char[10];
    }

    public Calculator(String calculate){
        //初始化栈空间
        operand = new double[10];
        operator = new char[10];
        this.calculate = calculate;//传入一个计算式
    }

    //设置计算式,也可以理解为添加一个计算式
    public void setCalculate(String calculate){
        this.calculate = calculate;
    }

    public String getCalculate(){
        return calculate;
    }

    public void setOperand(double[] operand){
        this.operand = operand;
    }

    public void setOperator(char[] operator){
        this.operator = operator;
    }

    /**
     * 将操作数放入栈中
     * @param element 插入的数据
     */
    private void push(double element){

        //判断栈满
        if(operandTop >= operand.length){
            expandCapacity(true);//操作数栈进行扩容
        }

        //放入元素
        operand[operandTop] = element;
        operandTop++;//操作数栈顶
    }

    //将操作符插入操作符栈中
    private void push(char element){

        //判断栈满
        if(operatorTop >= operator.length){
            expandCapacity(false);//操作符栈进行扩容
        }

        //插入操作符
        operator[operatorTop] = element;
        operatorTop++;//操作符栈顶加1
    }

    //操作数弹出
    private double popNumber(){

        return operand[--operandTop];

    }

    //操作符弹出
    private char popOperator(){

        return operator[--operatorTop];//只管弹出

    }

    /**
     * 对数组进行扩容
     * @param o true -> 操作数栈 false -> 操作符栈
     */
    private void expandCapacity(boolean o){

        //根据传入的参数决定array的数据类型
        if(o){
            double[] array = operand;
            //扩容成原来的数组的两倍
            double[] newArray = new double[array.length * 2];
            //将原来数组中的元素全部复制到新数组当中
            if (operandTop >= 0 || operatorTop >= 0){
                System.arraycopy(array, 0, newArray, 0, array.length);
                //将扩容后的数组的首地址赋值给array(该类的属性)
                setOperand(newArray);
            }
        }else{
            char[] array = operator;
            char[] newArray = new char[array.length * 2];
            //将原来数组中的元素全部复制到新数组当中
            if (operandTop >= 0 || operatorTop >= 0){
                System.arraycopy(array, 0, newArray, 0, array.length);
                //将扩容后的数组的首地址赋值给array(该类的属性)
                setOperator(newArray);
            }
        }
    }

    //返回结果
    public double getResult(){
        double result = 0.0;
        double num1;
        double num2;
        StringBuilder value = new StringBuilder();//保存的中间值


        if(calculate == null){
            //计算式为空
            return result;//结果为空,以0返回出去
        }else{

            //先检查计算式是否符合规范
            if(calculate.charAt(0) == '*' || calculate.charAt(0) == '/' || calculate.charAt(0) == '+'){
                throw new RuntimeException("计算式格式不准确!开头不允许出现+、*、/三种操作符,尾部只能是数字或右括号");
            }
            //检测尾部
            if (calculate.charAt(calculate.length() - 1) < '0'|| calculate.charAt(calculate.length() - 1) > '9'){
                //如果检测到计算式尾部是→括号,不会抛异常
                if(calculate.charAt(calculate.length() - 1) != ')'){
                    //开头不允许出现+、*、/三种操作符,尾部只能是数字或右括号
                    throw new RuntimeException("计算式格式不准确!开头不允许出现+、*、/三种操作符,尾部只能是数字或右括号");
                }
            }

            //判断计算式开头是数字?操作符?【遍历整个计算式】
            for(int i = 0;i < calculate.length();i++){
                //如果计算式以减号开头
                if(calculate.charAt(i) == '-'){
                    value.append(calculate.charAt(i));
                }else if(calculate.charAt(i) == '(' && calculate.charAt(i + 1) == '-'){
                    i++;
                    value.append(calculate.charAt(i));//将减号加入
                    i++;//判断下一个字符
                    //判断如果后面是数字,就加入value
                    while(calculate.charAt(i) >= '0' && calculate.charAt(i) <= '9'){
                        value.append(calculate.charAt(i));
                        i++;//依次判断下一个字符是否是数字,是数字添加进value,不是跳出循环
                    }
                    //将value值加入操作数栈中
                    if(value.charAt(0) == '-' && value.charAt(1) == '-'){
                        //连续的减号
                        String pushedValue;//放入栈中的值
                        pushedValue = value.substring(1);
                        push(Double.parseDouble(pushedValue));
                        push(value.charAt(0));//将减号压入符号栈中
                    }else{
                        push(Double.parseDouble(value.toString()));
                    }
                    value.delete(0,value.length());//清空
                    if(calculate.charAt(i) != ')'){
                        push('(');
                        i--;
                    }
                }else if(calculate.charAt(i) >= '0' && calculate.charAt(i) <= '9'){//判断是否是数字
                    //判断如果后面是数字,就加入value
                    while(calculate.charAt(i) >= '0' && calculate.charAt(i) <= '9'){
                        if(i == calculate.length() - 1){
                            //计算式最后1个数字
                            value.append(calculate.charAt(i));
                            i++;
                            break;//跳出循环
                        }
                        value.append(calculate.charAt(i));
                        i++;//依次判断下一个字符是否是数字,是数字添加进value,不是跳出循环
                    }
                    push(Double.parseDouble(value.toString()));
                    value.delete(0,value.length());//清空
                    i--;
                }else{//一些符号
                    if(operatorTop == 0){
                        //操作符栈没有符号
                        push(calculate.charAt(i));
                    }else if(priority(calculate.charAt(i)) == 1){//符号是(
                        push(calculate.charAt(i));
                    }else if(priority(calculate.charAt(i)) == 2){//符号是+或-
                        if(priority(operator[operatorTop - 1]) == 1) {//栈顶符号是(
                            push(calculate.charAt(i));
                        }else if(priority(operator[operatorTop - 1]) == 2 || //符号是+ -
                                priority(operator[operatorTop - 1]) == 3){   //符号是* /
                            //操作符个数大于1 以及操作数栈大于2,可以进行计算
                            while (operatorTop >= 1 && operandTop >= 2){
                                //判断一下当前操作符是+ - * /【在操作符栈中还有'('】
                                if(operator[operatorTop - 1] == '('){
                                    break;//如果栈顶是左括号,直接跳出循环
                                }
                                num1 = popNumber();//弹出两个数
                                num2 = popNumber();
                                push(twoCalculate(num1,num2,popOperator()));//进行相加,结果存入操作数栈
                            }
                            push(calculate.charAt(i));//新操作符进栈
                        }
                    }else if(priority(calculate.charAt(i)) == 3){//符号是* /
                        if(priority(operator[operatorTop - 1]) == 1) {//栈顶符号是(
                            push(calculate.charAt(i));
                        }else if(priority(operator[operatorTop -1]) == 2){//符号是+ -
                            push(calculate.charAt(i));//新操作符进栈
                        }else if(priority(operator[operatorTop -1]) == 3){//符号是* /
                            //操作符个数大于1 以及操作数栈大于2,可以进行计算
                            while (operatorTop >= 1 && operandTop >= 2){
                                //判断一下当前操作符是+ - * /【在操作符栈中还有'('】
                                if(operator[operatorTop - 1] == '('){
                                    break;//如果栈顶是左括号,直接跳出循环
                                }
                                num1 = popNumber();//弹出两个数
                                num2 = popNumber();
                                push(twoCalculate(num1,num2,popOperator()));//进行相加,结果存入操作数栈
                            }
                            push(calculate.charAt(i));//新操作符进栈
                        }
                    }else if(priority(calculate.charAt(i)) == 4) {//符号是)
                        do{//一直运算,直到遇到'('
                            //如果一直没有遇到'('
                            if(operatorTop <= 1){
                                throw new RuntimeException("计算式有误!()括号不对称");
                            }
                            num1 = popNumber();
                            num2 = popNumber();
                            push(twoCalculate(num1,num2,popOperator()));
                        }while (priority(operator[operatorTop - 1]) != 1);
                        popOperator();//操作符(出栈
                    }
                }
            }
        }

        //当操作符栈中还有操作符,一直计算
        while (operatorTop != 0){
            num1 = popNumber();
            num2 = popNumber();
            push(twoCalculate(num1,num2,popOperator()));
        }

        result = operand[operandTop - 1];

        return result;
    }

    /**
     * 优先级判断  【优先级由低到高:1 -- 4】
     * @param c 运算符
     */
    private int priority(char c){

        if(c == '(' || c == '('){
            return 1;
        }else if(c == '+' || c == '-'){
            return 2;
        }else if(c == '*' || c == '/'){
            return 3;
        }else if(c == ')' || c == ')'){
            return 4;
        }else{
            throw new IllegalArgumentException("参数错误!非运算符!");
        }
    }

    /**
     * 两个数进行计算
     * @param num1  传入的数字1
     * @param num2  传入的数字2
     * @param c     传入的运算符
     * @return      返回的结果
     */
    private double twoCalculate(double num1,double num2,char c){

        double result;

        switch (c){
            case '+':
                result = num1 + num2;
                break;
            case '-':
                result = num1 - num2;
                break;
            case '*':
                result = num1 * num2;
                break;
            case '/':
                if(num2 == 0){
                    throw new IllegalArgumentException("除数不能为0!");
                }
                result = num1 / num2;
                break;
            default:
                throw new IllegalArgumentException("运算符不是 + - * /");
        }

        return result;//返回结果
    }

}

 2.测试计算器

TestCalculate.java

 

package com.application;

/*
    测试计算器
 */

public class TestCalculate {

    public static void main(String[] args) {

        Calculator calculator = new Calculator("1+(2*3+1)+(2*32+12)+129+(12*89)");
        double result = calculator.getResult();//获取结果
        System.out.println(calculator.getCalculate() + "=" + result);

    }
}

3.运行截图

 

 

完 

posted @ 2022-04-02 15:20  辰梦starDream  阅读(1)  评论(0编辑  收藏  举报  来源