递归前缀解析器阶乘 Java

Recursive prefix parser factorial Java

我最近开始在 uni 学习 java,我们必须做的一项任务是理解递归并将阶乘函数添加到这个波兰符号代码中。我尝试了各种方法,这是最新的:

public class PolishNotation {

    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.println("Please enter the operators");
            System.out.println("for operators +, -, *, and !");
            System.out.println("Leave spaces between all operators and digits");
            System.out.print("expression: ");
            System.out.println("value = " + evaluateEXP(scanner));
        }
    }

    //input contains the expression user has entered
    public static int evaluateEXP(Scanner scanner) {
        //checks if there is another digit after current one
        //allows expression to be looked at from right to left
        if (scanner.hasNextInt())
            return scanner.nextInt();

        //if there is another digit after current one then
        //operands and operators are established
        char operator = scanner.next().charAt(0);
        int operand1 = evaluateEXP(scanner);
        int operand2 = evaluateEXP(scanner);
        return evaluateOP(operator, operand1, operand2);
    }

    //operator has to be one of +, - , * or ! otherwise error is given
    private static int evaluateOP(char operator, int operand1, int operand2) {
        if (operator == '+')
            return operand1 + operand2;
        if (operator == '-')
            return operand1 - operand2;
        if (operator == '*')
            return operand1 * operand2;
        if (operator == '/')
            return operand1 / operand2;
        if (operator == '!')
            //if ! used then uses factorial method
            return factorial(operand1);
        //RunTimeException allows to return an error string in a int "type" method
        throw new RuntimeException("operator not allowed for this language");
    }

    private static int factorial(int n) {
        return n == 1 ? 1 : factorial(n - 1) * n;
    }

}

没有错误,但是没有结果,所以我猜它陷入了无限循环。这段代码的想法是,如果我这样做了! + 3 2 它应该做 !5 所以 return 120 并且我不能使用 while 或 for 循环。其余操作数有效,只是阶乘无效。

public static int factorial(int n) {
    if(n==1){
        return 1;
    }
    // the next line is wrong.  I've removed a set of parentheses to make it more clear 
    int output =  factorial((n-1)*n);
    return output;
}

If 强烈推荐 运行 通过您脑海中的代码。如果我将 2 传递给您的方法,递归调用 factorial() 的值是什么?提示:它不是 1.

public static long fact(int n) {
    return n == 0 ? 1L : n * fact(n - 1);
}

最好用long作为return类型,因为17!大于Integer.MAX_VALUE

问题是在 evaluateEXP 中,您的代码总是需要 2 个操作数。然而 ! 只需要一个操作数,所以如果你输入类似 ! 5 的东西,它会等待更多的输入。

解决方法是检查运算符是一元还是二元,如果是一元则只接受一个操作数。以下是重构代码以实现此目的的几种方法:

1) 检查 evaluateEXP 方法中的运算符,如果第二个操作数是二进制的(在您的情况下不是 !),则只获取第二个操作数:

//input contains the expression user has entered
public static int evaluateEXP(Scanner scanner) {
    //checks if there is another digit after current one
    //allows expression to be looked at from right to left
    if (scanner.hasNextInt())
        return scanner.nextInt();

    //if there is another digit after current one then
    //operands and operators are established
    char operator = scanner.next().charAt(0);
    int operand1 = evaluateEXP(scanner);
    int operand2 = 0;
    //only take second operand if operator is not unary
    if (operator != '!') {
        operand2 = evaluateEXP(scanner);
    }
    return evaluateOP(operator, operand1, operand2);
}

2) 将scanner传给evaluateOP,让它直接取操作数:

//input contains the expression user has entered
public static int evaluateEXP(Scanner scanner) {
    //checks if there is another digit after current one
    //allows expression to be looked at from right to left
    if (scanner.hasNextInt())
        return scanner.nextInt();

    //if there is another digit after current one then
    //operands and operators are established
    char operator = scanner.next().charAt(0);
    return evaluateOP(operator, scanner);
}

//operator has to be one of +, - , * or ! otherwise error is given
private static int evaluateOP(char operator, Scanner scanner) {
    if (operator == '+')
        return evaluateEXP(scanner) + evaluateEXP(scanner);
    if (operator == '-')
        return evaluateEXP(scanner) - evaluateEXP(scanner);
    if (operator == '*')
        return evaluateEXP(scanner) * evaluateEXP(scanner);
    if (operator == '/')
        return evaluateEXP(scanner) / evaluateEXP(scanner);
    if (operator == '!')
        //if ! used then uses factorial method
        return factorial(evaluateEXP(scanner));
    //RunTimeException allows to return an error string in a int "type" method
    throw new RuntimeException("operator not allowed for this language");
}

3) 在第二个解决方案的基础上,您还可以合并这两种方法,因为它们之间的联系非常紧密:

//input contains the expression user has entered
public static int evaluateEXP(Scanner scanner) {
    //checks if there is another digit after current one
    //allows expression to be looked at from right to left
    if (scanner.hasNextInt())
        return scanner.nextInt();

    //if there is another digit after current one then
    //operands and operators are established
    char operator = scanner.next().charAt(0);

    if (operator == '+')
        return evaluateEXP(scanner) + evaluateEXP(scanner);
    if (operator == '-')
        return evaluateEXP(scanner) - evaluateEXP(scanner);
    if (operator == '*')
        return evaluateEXP(scanner) * evaluateEXP(scanner);
    if (operator == '/')
        return evaluateEXP(scanner) / evaluateEXP(scanner);
    if (operator == '!')
        //if ! used then uses factorial method
        return factorial(evaluateEXP(scanner));
    //RunTimeException allows to return an error string in a int "type" method
    throw new RuntimeException("operator not allowed for this language");
}