用于求解表达式的简单Java计算器

用于求解表达式的简单Java计算器,java,loops,arraylist,switch-statement,calculator,Java,Loops,Arraylist,Switch Statement,Calculator,我正在做一个计算表达式的计算器。我正在想办法让它按PEMDAS的顺序计算。我有一个for循环遍历数组列表,还有一个开关调用一个进行数学运算的类。我尝试过if语句,但一直没有弄明白 如何更改此项以确保表达式按正确顺序求解?以下是我目前掌握的情况: /* Peter Harmazinski Simple Calculator This program solves expressions */ import java.util.*; public class SimpleCalculator2

我正在做一个计算表达式的计算器。我正在想办法让它按PEMDAS的顺序计算。我有一个for循环遍历数组列表,还有一个开关调用一个进行数学运算的类。我尝试过if语句,但一直没有弄明白

如何更改此项以确保表达式按正确顺序求解?以下是我目前掌握的情况:

/*
Peter Harmazinski
Simple Calculator

This program solves expressions
*/

import java.util.*;

public class SimpleCalculator2 {
    static SimpleMath math = new SimpleMath();

    public static void main(String[] args) {
        Scanner console = new Scanner(System.in);
        boolean again = true;
        double number1 = 0.0;
        double number2 = 0.0;
        double answer = 0.0;
        double results = 0.0;
        String delims = "[ ]+";

        getIntroduction();

        while (again) {
            System.out.println("Please enter your expression.");
            String input = console.nextLine();
            System.out.println("This is the user's input: " + input);

            //Parses string into array list
            List<String> list = new ArrayList<String>(Arrays.asList(input.split(delims)));
            System.out.println("list: " + list);

            results = doMath(list, number1, number2);
            getResults(results);
        }
        console.close();
    }

    public static void getIntroduction() {
        System.out.println("This is a simple calculator that solves expressions.");
    }

    //Traverses array list to identify operators and does math for surrounding numbers
    //then answer is inserted in i-1 element and the elements i and i+1 are deleted

    public static double doMath(List<String> list, double number1, double number2) {
        double answer = 0.0;
        double results = 0.0;
        while (list.size() > 1) {
            for (int i = 0; i < list.size(); i++) {
                    switch (list.get(i)) {
                        case "*" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.multiply(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        case "/" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.divide(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        case "+" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.add(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        case "-" :
                            number1 = Double.parseDouble(list.get(i - 1));
                            number2 = Double.parseDouble(list.get(i + 1));
                            answer = math.subtract(number1, number2);
                            System.out.println(answer);
                            list.add(i - 1, Double.toString(answer));
                            list.subList(i, i + 3).clear();
                            System.out.println(list);
                            break;
                        }
                }   
            }   
        return answer;
    }

    public static void getResults(double results) {
        System.out.println("Results are: " + results);
    }
}

我认为实现这一点的一个相当标准的算法是Dijkstra的调车场算法,然后是后缀评估。您可以在这里阅读,伪代码也在这里,但您可能需要对基本数据结构有一些了解:

如果您不知道堆栈、队列和后缀符号,您可以编写一个更慢、更直接但更混乱的实现。有一次我用sin、cos、trig、log进行了尝试,结果代码运行正常,但我不会再试一次

基本上,其思想是找到只有1个运算符的最高优先级表达式,对其求值,然后用它替换它。下面是一些伪代码:

input = [user input]
while expression still contains (, ), +, -, *, or /:
    toEvaluate = highest priority expression with 1 operator (e.g. 1+2, or 2*3)
    calculate the decimal value of toEvaluate
    modify input so that you replace toEvaluate with its decimal value
请注意,在doMath实现中,在for循环中,只要看到所有操作符,就可以对它们进行求值。例如,考虑

1+2*3


您将首先看到+并计算1+2,然后将结果乘以3。相反,您需要首先遍历整个列表,找到最高优先级的运算符,对其求值,然后从头开始重新开始。

既然您要将其输入字符串,为什么不创建一个for循环,循环遍历每个字符

// This for loop will get you the string with only one operator in it.
// EX: 30+32
// You will have to find some way to compute this string.
for(int i = 0; i < userInput.length(); i++)
{
   //int a will be the INDEX of the first operator
   //int b will be the INDEX of the place where a new operator comes up 
   char c = userInput.getCharAt(i);
   a = 0;
   //I'm just gonna do it with + and - for now. Add any other operators.
   if(c == '+' || c == '-')
   {
       b = i;
       String stringToCompute = userInput.substring(a,b);
       //Find some way to take the string there then compute it. 
       //Maybe another for loop with stringToCompute to find where the
       // operator is and then add/subtract the two doubles.  

       // Now reset it 
       a = i;
       b = null;
   }
}

以下是解决此问题的几种可能的设计:

您可以将处理分为两部分:解析和评估。在解析阶段,您将字符串转换为表示如何对其求值的数据结构。在计算阶段,遍历树并计算表达式

您可以按运算符拆分列表以计算最后一个加号和减号,计算每个段的次数并进行除法。如果设计得当,这可能是递归的

第一个选项更好,因为它更具可扩展性,但也更易于实现。以下是通过解析和评估生成的示例数据结构:

interface Term {
    double getValue();
}

enum Operator {
    MULTIPLY, DIVIDE, ADD, SUBTRACT;
    double getValue(List<Double> operands) {
        ...
    }
}

class Operation implements Term {
    List<Term> operands;
    Operator operator;
    double getValue() {
        return operator.getValue(operands);
    }
}

class Constant implements Term {
    private final double value;
    double getValue() {
        return value;
    }
}

顺便说一句:这是一个常见的问题,而且比你想象的要复杂。这不是一个骗局,但这个问题可能会有所帮助。对不起,我应该更清楚。。。在我学习数据结构和算法之前,我尝试过这个。我不会再尝试了,因为我现在知道了堆栈、队列、后缀符号和调车场算法。但我建议OP尝试一下,如果他/她没有为了获得经验而做数据结构和算法。同样,为了计算5*4,你不再做5+5+5+5,因为你知道乘法。在你了解乘法之前,你给自己加了4次5来练习。不管怎么说,这是一次毫无成果的讨论。非常感谢。这很有帮助。如果我有必要的声誉,我会投赞成票。没问题。很高兴我能帮忙。如果您认为这回答了您的问题,您可以通过单击复选标记接受这一答案。您还将获得+2声誉。感谢您让我知道!在示例代码中,操作数可以是十进制数。你打算如何应对这种情况。