我正在编写一个函数,如果数字为素数则返回true,否则返回false
这是我目前的代码:
public static boolean checkPrime(int n, int currDivisor){
if(n < 2){
return true;
}
if(currDivisor == (n/2)){
return true;
}
else if(n % currDivisor == 0 ){
return false;
}
else{
return checkPrime(n, currDivisor + 1);
}
}
public static void main(String[] args){
System.out.println(checkPrime(23352, 2));
}
它适用于很多测试用例,除了像“1000000007”这样的数字,我得到内存不足错误。我怎么能调整这段代码以便在空间方面更有效?
答案 0 :(得分:3)
根本问题在于递归不是正确的方法。原始性测试不是一个递归问题,对于大数字,您总是会非常快地超过可用存储空间。我建议你在网上做一些关于&#34; primality testing&#34;的主题的研究。
关于决定问题是否递归的经验法则,我已经做了这么久,我不确定我能表达什么是完全直观的,所以我会让别人这样做。
然而,值得指出的是,在数学上递归的一些问题具有计算解决方案,其中迭代远比天真递归好得多。素数(哈!)的例子是斐波纳契数。对于大n,天真的递归解决方案会占用内存并执行冗余计算,而迭代解决方案则更快更好。
答案 1 :(得分:1)
我看到的第一个问题是你的程序是错误的。它似乎认为0,1和&amp; 4是素数而3是素数。我看到的第二个问题是浪费堆栈帧在递归之前没有正确处理简单的情况。这是我对代码的修改:
public static boolean checkPrime(int n) {
return checkPrime1(n, 3);
}
public static boolean checkPrime1(int n, int currDivisor) {
if (n < 2) {
return false;
}
if (n % 2 == 0) {
return (n == 2);
}
if (currDivisor * currDivisor > n) {
return true;
}
if (n % currDivisor == 0) {
return false;
}
return checkPrime1(n, currDivisor + 2);
}
至于处理:
System.out.println(checkPrime(1000000007));
你仍然会得到java.lang.StackOverflowError
,但这不是故事的结局。大多数语言都会决定为特定目的分配多少内存。像Perl这样罕见的语言会将内存重新分配给最需要它的资源,而不是对程序的行为方式做出假设。
您可以更改分配给Java堆栈的内存量 - 调用java
并使用-Xss2m
参数分配足够的额外堆栈,让您测试1000000007(true
。 )
如果您将上面的三个int
声明更改为long
,只要展开堆栈,您就可以测试2547487897L
或更大的数字({{1}在这种情况下。)
我不是说这对于递归是一个很好的问题,事实并非如此。但是,如果您要使用递归,请明智地使用它。这是一个糟糕的递归,它给递归一个坏名字。存在效率低的递归Fibonnaci算法(通常是双递归)和有效(单递归)算法。递归代码通常最适合递归数据。
有些语言(一般来说还不是Java)可以将上面的代码优化为尾递归,并使其有效地实现迭代性能。