我正在尝试制作一种方法,告诉我天气与否是一个数字是素数的真假。这是代码:
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
正确的?
还是有更有效的方式 这件事让我失踪了 完全?
答案 0 :(得分:6)
在prime
函数中,有四种可能的代码路径,其中一种不返回任何。这就是错误消息所抱怨的内容。您需要替换:
prime (a, b-1) ;
使用:
return prime (a, b-1) ;
else if (b>1)
案例中的。
话虽如此,这实际上并不是计算数字是否为素数的好方法。问题是每个递归调用都会分配一个堆栈帧,如果你想弄清楚99,999,999是否为素数,你会遇到严重的堆栈溢出问题?
递归对于某个问题子集来说是一个非常好的工具,但您需要了解堆栈深度。至于更有效的解决方案,您可以执行许多测试来确定一个数字 not prime,然后只用蛮力测试检查其他数据。
您应该注意的一件事是首先检查较小数字的可分性,因为这会更快地缩小您的搜索范围。并且不要使用乘法所做的除法,乘法通常更快(但并非总是如此)。
还有一些可能是偷偷摸摸的伎俩:
有一些更复杂的可分性检查规则。如果您取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;
}
一旦确定该数字不均匀,就可以跳过所有偶数。这将使需要检查的数字减半。