我的语法有什么问题,我这样做有效吗?

时间:2010-03-10 01:03:02

标签: java syntax methods

我正在尝试制作一种方法,告诉我天气与否是一个数字是素数的真假。这是代码:

class prime
{

    public static boolean prime (int a, int b) 
    { 
        if (a == 0) 
        {
            return false; 
        }
        else if (a%(b-1) == 0) 
        {
            return false; 
        }
        else if (b>1) 
        {
            prime (a, b-1) ;
        }
        else
        {
            return true; 
        }

    }

    public static void main (String[] arg) 
    {
        System.out.println (prime (45, 45)) ; 
    }
}

当我尝试编译时,我收到此错误消息:

prime.java:23: missing return statement
    }
    ^
1 error

我可能会错误地解释错误消息的内容,但在我看来,由于我对每个可能的条件都有一个return语句,因此没有丢失的return语句。如果a为0然后它返回false,如果不是那么它检查a是否可被b分割,如果是,那么它返回如果不是那么如果b大于1则重新开始。如果b不大于1,它也会返回。

  • 此外,似乎有点混乱 使这个方法采取两个整数 是相同的int。

  • 我的语法有什么问题/为什么我收到错误信息?是否有一种方法可以使我在main中使用的方法只需要一个int(也许另一种方法将该int拆分为两个克隆,然后传递给public static boolean prime正确的?

  • 还是有更有效的方式 这件事让我失踪了 完全?

8 个答案:

答案 0 :(得分:6)

prime函数中,有四种可能的代码路径,其中一种不返回任何。这就是错误消息所抱怨的内容。您需要替换:

prime (a, b-1) ;

使用:

return prime (a, b-1) ;
else if (b>1)案例中的

话虽如此,这实际上并不是计算数字是否为素数的好方法。问题是每个递归调用都会分配一个堆栈帧,如果你想弄清楚99,999,999是否为素数,你会遇到严重的堆栈溢出问题?

递归对于某个问题子集来说是一个非常好的工具,但您需要了解堆栈深度。至于更有效的解决方案,您可以执行许多测试来确定一个数字 not prime,然后只用蛮力测试检查其他数据。

您应该注意的一件事是首先检查较小数字的可分性,因为这会更快地缩小您的搜索范围。并且不要使用乘法所做的除法,乘法通常更快(但并非总是如此)。

还有一些可能是偷偷摸摸的伎俩:

  • 除了2以2,4,6,8或0结尾的每个数字都是非素数。
  • 5以5之外的每个数字都是非素数。 仅这两项规则将使您的搜索空间减少60%。假设您将测试编号作为字符串,即使在转换为整数类型之前测试该字符串的最后一位数字也是一件简单的事情。

有一些更复杂的可分性检查规则。如果您取9的倍数并将所有数字相加以得到一个新数字,那么再次执行该数字,然后继续前进直到您有一个数字,您将发现它总是为9。

这将使您的搜索空间再减少10%,尽管需要花费更多时间。请记住,这些检查仅对非常大的数字有利。例如,32位整数的优点并不那么好,因为预先计算的位图在那里效率会更高(见下文)。

为了简单起见,我将使用以下迭代解决方案:

public static boolean prime (int num) {
    int t = 2;
    while (t * t <= num) {
        if ((num % t) == 0) {
            return false;
        }
        t++;
    }
    return true;
}

如果您希望代码中有真正的速度,请不要每次都计算它。计算一次,在您感兴趣的范围内创建所有素数的位数组(其中一个筛子方法会这样做),然后根据该位数组检查您的值。

如果您甚至不希望每次程序启动时计算数组的成本,请执行一次并将位数组保存到磁盘文件中,并在程序启动时加载它。

我实际上有一个文件中前100万个素数的列表,使用grep来查找数字是否为素数比使用一些代码来计算它更容易,更快:-)


至于为什么你的算法(用return语句修复)坚持7不是素数,它会坚持每个数字都是非素数(没有用负数检查)数字,我很确定它们会引起一些严重的问题 - 你的第一次检查应该是if (a < 1) ...)。

让我们来看看你致电prime(3,3)时会发生什么。

第一次,它达到第三个条件,因此调用prime(3,2)

然后它会点击第二个条件,因为3 % (2-1) == 0为真(N % 1 总是 0)。

所以它返回false。这可能可以通过将第三个条件更改为else if (b>2)来解决,尽管我没有彻底测试过,因为我认为递归解决方案无论如何都不是一个好主意。


以下完整的代码片段可以满足您的需求,但我很感激您的好奇心,想知道您做错了什么。这是一个真正打算成为优秀代码切割者的人的标志。

public class prime
{
    public static boolean isPrime (int num) {
        int t = 2;
        while (t * t <= num) {
            if ((num % t) == 0) {
                return false;
            }
            t++;
        }
        return true;
    }


    public static void main (String[] arg) 
    {
        System.out.println (isPrime (7)) ; 
    }
}

答案 1 :(得分:5)

你似乎认为,因为递归最终会找到一个基本案例,它将触及一个return语句,然后该返回将在所有递归调用中冒出来。这不是真的。每个递归调用必须传递出如下结果:

return prime(a, b - 1);

答案 2 :(得分:4)

如果b大于1,则您的函数不会返回任何内容。

可能是return prime (a, b-1) ;

答案 3 :(得分:3)

为了提高效率,请多考虑一下您的情况。你真的需要测试从2到N的每个因素吗?是否有一个不同的停止点可以帮助更快地完成质数测试?

要制作更好的API,请考虑将递归方法设为私有,并使用有助于引导进程的公共入口点。例如:

public static boolean prime(int n) {
  return recurse(n, n);
}

private static boolean recurse(int a, int b) {
 ...
}

制作方法private意味着无法从另一个类调用它。它对班级用户来说实际上是不可见的。这里的目的是通过提供公共帮助方法来隐藏“丑陋”的额外参数。

考虑一些复合数的因素。 10个因素为5×2。 12个因素为6×2。 14个因素到7×2。现在想想25个因素到5×5。 9怎么样?你看到一个模式吗?顺便说一句,如果这不是作业,请告诉我。做这个说教对我来说很难。

答案 4 :(得分:2)

为了回答7为什么不起作用,假装你是计算机并完成你的逻辑。这是你写的。

class prime
{

    public static boolean prime (int a, int b) 
    { 
        if (a == 0) 
        {
            return false; 
        }
        else if (a%(b-1) == 0) 
        {
            return false; 
        }
        else if (b>1) 
        {
            // Have to add the return statement
            // here as others have pointed out!
            return prime(a, b-1);
        }
        else
        {
            return true; 
        }

    }

    public static void main (String[] arg) 
    {
        System.out.println (prime (45, 45)) ; 
    }
}

所以让我们从7开始。

if(7 == 0) // not true, don't enter this block
else if(7 % 6 == 0) // not true
else if(7 > 1) // true, call prime(7, 6)

if(7 == 0) // not true, don't enter this block
else if(7 % 5 == 0) // not true
else if(6 > 1) // true, call prime(7, 5)

if(7 == 0) // not true, don't enter this block
else if(7 % 4 == 0) // not true
else if(5 > 1) // true, call prime(7, 4)

...继续打电话给素数(7,2)

if(7 == 0) // not true, don't enter this block

<强> else if(7 % 1 == 0) true, return false

当你开始调用prime(n, 2)时,它总会返回false,因为你有一个逻辑错误。

答案 5 :(得分:0)

您的递归方法必须返回一个值才能展开。

    public static boolean prime (int a, int b) 
{
    if (a == 0) 
    {
        return false; 
    }
    else if (a%(b-1) == 0) 
    {
        return false; 
    }
    else if (b>1) 
    {
        return prime (a, b-1) ;
    }
    else
    {
        return true; 
    }

}

我可能会用不同的方式编写它,但这就是你无法编译代码的原因。

答案 6 :(得分:0)

我认为原来的问题已经回答了 - 您需要在return的正文中插入else if (b>1) - 我只想指出,当给定1作为值时,您的代码仍然会崩溃b,自ArithmeticException以来抛出a%(b-1)将被评估为a%0,从而导致除以零。

你可以通过制作第一个if语句if (a == 0 || b == 1) {}来避免这种情况 这不会改进程序找到素数的方式,它只是确保有一种方法可以使它崩溃。

答案 7 :(得分:0)

与@ paxdiblo的答案类似,但效率稍高。

public static boolean isPrime(int num) {
    if (num <= 1 || (num & 1) == 0) return false;
    for (int t = 3; t * t <= num; t += 2)
        if (num % t == 0)
            return false;
    return true;
}

一旦确定该数字不均匀,就可以跳过所有偶数。这将使需要检查的数字减半。