Return语句没有正确终止递归方法

时间:2018-03-31 05:08:21

标签: java if-statement return primes

我有一个方法 getNextPrime(int num),它应该在方法收到的值之后识别最接近的素数。

如果 num 是偶数,它会增加它并再次调用自身。如果它是奇数,它将运行for循环以检查它是否可被3和 num 的半值之间的奇数整除。如果是,那么它将 num 增加2并且该方法将再次调用自身,否则它将返回新的 num 值,这是一个素数。

问题是,当程序到达return语句时,它将跳转到if语句并返回 num + 1的原始值。我已经调试了一段时间了只是没有意义。无论我在何处放置return语句,该方法只是跳转到if语句而不是终止方法并将值返回到调用它的位置。

public int getNextPrime(int num){

    if(num % 2 == 0){
        //even numbers are not prime

        getNextPrime(++num);
    }
    else{

        for(int i = 3; i < (num + 1) / 2; i += 2){

            if(num % i == 0) {
                getNextPrime(num += 2); //consider odd numbers only
            }
        }
    }

    return num; //jumps to if and terminates
}

但是,如果我将else语句更改为单独的if语句, if(num%2!= 0)就可以。

为什么会这样?

*注意 - 给出的方法的值大于3,1,2和3是素数的事实并不重要。

4 个答案:

答案 0 :(得分:1)

这里只有一个结构问题。到达单个返回不会折叠整个调用堆栈,它只返回到先前的调用。

每次都需要保存调用getNextPrime()的结果并将其用作返回值,因此实际找到的值会沿着调用链传回并返回给初始调用者。就目前而言,您只返回传入的数字,因为您从未修改它。

修复是一个非常简单的修改。你在哪里

getNextPrime(++num);

... and ...

getNextPrime(num+2);

替换它们
return getNextPrime(++num);

... and ...

return getNextPrime(num+2);

您选择的算法存在的问题是效率低下。您需要仅使用较小的素数来测试可分性,而不是所有奇数,并且只能使用原始数字的平方根

实施留作练习。

答案 1 :(得分:0)

您需要退出递归循环并在找到素数后立即返回该数字。有一件事你可以尝试Jim建议的解决方案,如果你得到相同的素数,如果最初用素数调用递归方法,你可以做以下几点来防止:

int num = 11;
int nextPrime = getNextPrime (num);
nextPrime =  (nextPrime == num) ? getNextPrime (num + 1) : nextPrime;

另一种(有点脏)的方法是在找到素数时设置一个标志,然后阻止执行除return语句之外的任何其他代码。像这样:

static boolean primeFound = false;

    public static int getNextPrime(int num) {
        if (!primeFound) {
            // incrementing num here to prevent returning the same number
            // if this method was initially called with a prime number
            num += 1;
            if (num % 2 == 0 && num != 2) {
                return getNextPrime(num);
            }
            for (int i = 3; i < (num / 2) + 1; i += 2) {
                if (num % i == 0) {
                    return getNextPrime(num);
                }
            }

            primeFound = true;
        }
        return num;
    }

答案 2 :(得分:0)

让我们在使用参数8;

调用函数时,尝试查看调用堆栈

第一个电话是:getNextPrime(8)。由于数字是偶数,函数进入if部分并使用getNextPrime(9)再次调用自身。这一次,else部分启动,检查for循环中的可分性,发现9是可分的,因此调用getNextPrime(11)。现在,getNextPrime(11)再次执行else和for循环,发现11是素数并将数字11返回给调用者,但如果仔细观察,则不要将此值存储在变量中,即num变量在getNextPrime调用中是9,当getNextPrime(9)返回时,它将该值返回到getNextPrime(8)。在你的getNextPrime(8)中,你还没有真正存储从递归调用堆栈返回的num变量。你只是返回在该函数中定义的num变量,在调用getNextPrime(11)之前你恰好增加了这个值,所以这个值是9,返回9。

下面给出了使用相同if else块修正的程序供您参考。

public static int genNextPrime(int num) {
    if (num % 2 == 0) {
        num = genNextPrime(++num);
    } else {
        for (int i = 3; i < (num + 1) / 2; i += 2) {
            if (num % i == 0) {
                num += 2;
                num = genNextPrime(num);
            }
        }
    }
    return num;
}

答案 3 :(得分:-1)

你的return语句工作正常,但是你已经离开了你的逻辑中的1,2和3。 2是偶数素数,1不是素数。