我正在做Euler项目的问题7。我应该做的是计算10,001 st 素数。 (素数是一个大于1的整数,只能被自身和一个整除。)
这是我目前的计划:
public class Problem7 {
public static void main(String args[]) {
long numberOfPrimes = 0;
long number = 2;
while (numberOfPrimes < 10001) {
if (isPrime(number)) {
numberOfPrimes++;
}
number++;
}
System.out.println("10001st prime: " + number);
}
public static boolean isPrime(long N) {
if (N <= 1)
return false;
else
return Prime(N, N - 1);
}
public static boolean Prime(long X, long Y) {
if (Y == 1)
return true;
else if (X % Y == 0)
return false;
else
return Prime(X, Y - 1);
}
}
找到100个 th 素数时可以正常工作,但运行非常大的输入(例如10,001)会导致堆栈溢出。为什么,我该如何解决这个问题?
答案 0 :(得分:30)
我认为问题在于你递归调用Prime
来确定一个数字是否为素数。因此,要确定数字1000是否为素数,您将递归调用Prime
1000次。每次递归调用都需要将数据保存在堆栈中。堆栈只有这么大,所以最终你的堆栈空间不足以继续进行递归调用。尝试使用迭代解决方案而不是递归解决方案。
答案 1 :(得分:8)
Java源代码:
public class Main {
public static void main(String args []){
long numberOfPrimes = 0;
int number = 1;
int maxLimit = 10000000;
boolean[] sieve = new boolean[maxLimit];
for ( int i = 2; i < maxLimit; i++ ) {
if ( sieve[i] == true ) continue;
numberOfPrimes++;
if ( numberOfPrimes == 10001 ) {
number = i;
break;
}
for ( int j = i+i; j < maxLimit; j += i )
sieve[j] = true;
}
System.out.println("10001st prime: "+ number);
}
}
答案 2 :(得分:4)
您应该将目前为止所有的素数保存到查找列表中,因此您将检查该数字是否除以该列表中的数字。如果不是,这是一个素数 - 请将其添加到列表中
另一个想法是将number++;
替换为number += 2;
,并且只要偶数为3
的数字不是素数,就会从2
开始检查。
答案 3 :(得分:2)
我最近解决了这个问题。我建议使用Sieve of Eratosthenes生成素数,比如所有素数&lt;百万。它不是一个难以实现的算法,而且它对于你需要的素数来说相当快。
答案 4 :(得分:2)
某些语言的编译器(例如许多函数和半功能语言,如Lisp)将转换尾部递归,就像您已经习惯进行迭代一样,但(显然)Java编译器并没有为您做到这一点。因此,每次递归调用都使用堆栈空间,最终会耗尽并且堆栈溢出。
当然,对于大多数用途,你想要使用不同的算法 - 你现在正在使用的是非常糟糕的事情。至少,您只需要检查奇数,直到您正在测试的数字的平方根...
答案 5 :(得分:1)
你测试素数的策略是用每个较小的自然数检查它的可分性。
如果你将你的策略转移到只用每个较小的素数来测试可分性,那么你将节省大量的计算。
答案 6 :(得分:1)
import java.util.*;
public class LargestPrime {
public static boolean isPrime(long s) {
for(long i = 2; i < s; i++) {
if((s % i) == 0) return false;
}
return true;
}
public static void main(String[] args) {
LargestPrime p = new LargestPrime();
LinkedList<Long> arr = new LinkedList<Long>();
for(long j = 2; j <= 999999; j++) {
if(isPrime(j)) arr.add(j);
}
// System.out.println("List of Prime Number are: "+ arr);
long t = arr.get(10001);
System.out.println("The Prime Number At 10001st position: " + t);
}
}
答案 7 :(得分:0)
为了解决这个问题,你将不得不从递归解决方案切换到迭代解决方案。 (每个递归算法也可以迭代表示。)
由于函数Prime是递归的,因此对它自己调用的次数总会有系统限制。
但是,您的系统上可能有足够的内存来达到10001. Java允许您设置VM使用的最大内存量(堆栈,堆等)。增加堆栈内存数量,你可能会成功。见本页
http://docs.sun.com/source/817-2180-10/pt_chap5.html
用于某些Java VM选项。
答案 8 :(得分:0)
您始终可以使用Rabin-Miller素性测试。这是一个非常容易实现的算法,速度非常快,但理解它的工作方式有点困难。
答案 9 :(得分:0)
package problems;
public class P_7 {
/**
* @param args
*/
public static boolean prime(double num)
{
double x=2;
double limit=(int) ((num/2)-(num/2)%1);
while(x<=limit)
{
if(num%x==0)
return false;
x++;
}
return true;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int i=1;
int j=3;
while(i<=10000)
{
if(prime(j))
{
System.out.println(i);
i++;
System.out.println(j);
}
j++;
}
}
}
这是我的工作答案。
答案 10 :(得分:0)
问题在于递归定义的Prime(X,Y)
函数,但也在于所使用的算法。在调用堆栈耗尽之前,Java的函数调用机制只能容纳递归深度,导致“堆栈溢出”错误。
足以测试对于所测试数字的平方根以下的所有数字的可分性。就OP代码而言,这意味着不是从Prime(N,N-1)
开始,而是从Prime( N, floor( sqrt( N+1)) )
开始。仅此更改就足以防止此特定任务的SO错误,因为递归深度将从10000更改为100。
算法问题只能从那里开始。 Prime(X,Y)
代码计算 down ,从而首先按较大的数字测试数字。但更常见的是较小的因素;计数应该从最小可能因子2(对于50%的数字遇到), 向上 到候选数字的sqrt
进行。该函数也应该在此机会重写为简单的while
循环。
接下来简单而明显的改进是完全忽略偶数。已知2是素数;所有其他的都没有。这意味着从numberOfPrimes = 1; number = 3;
开始循环并按number += 2
向上计数仅枚举奇数,isPrime(N)
仅通过奇数数字测试其可分性,在以while
开头的X = 3
循环中,测试N % X
并按X += 2
计算。
或者在伪代码(实际上是Haskell)中,原始代码是
main = print ([n | n<-[2..], isPrime(n)] !! 10000) where
isPrime(n) = _Prime(n-1) where
_Prime(y) = y==1 || (rem n y > 0 && _Prime(y-1))
-- 100:0.50s 200:2.57s 300:6.80s 10000:(projected:8.5h)
-- n^2.4 n^2.4
建议的修复:
main = print ((2:[n | n<-[3,5..], isOddPrime(n)]) !! 10000) where
isOddPrime(n) = _Prime(3) where
_Prime(y) = (y*y) > n || (rem n y > 0 && _Prime(y+2))
-- 100:0.02s 200:0.03s 300:0.04s 5000:3.02s 10000:8.60s
-- n^1.5
显示的时间是针对GHCi中的非编译代码(在慢速笔记本电脑上)。 Empirical local orders of growth被视为log(t2/t1) / log(n2/n1)
。更快的是通过素数进行测试,而不是通过奇数进行测试。
btw, 原始代码不会打印出第10001个素数,而是高于它的数字。
答案 11 :(得分:0)
在C ...你可以做更短的版本,但无论如何:D ..
#include <stdio.h>
#include <stdlib.h>
prost_br(int p)
{
int br=0;
for(int i=2;i*i<=p;i++)
if(p%i==0)
br++;
if(br==0)
return 1;
return 0;
}
int main()
{
long i=1;
int br=0;
FILE *a;
a=fopen("10001_prst_numbers.txt","w");
if(a==NULL){printf("\nError!\a\n"); exit(1);}
while(br!=10001)
{
i++;
if(prost_br(i))
{
br++;
fprintf(a,"%d ",i);
}
}
char s[]={"10001th prime number is: "};
fprintf(a,"\n%s %d",s,i);
fprintf(stdout,"\n10001th prime number is: %d\n\a",i);
fclose(a);
system("Pause");
}
答案 12 :(得分:0)
public class progs {
public int nthPrime(int nth) {
int ctr = 0;
int num = 0;
int x = 2;
int infinite = 15; // initial value good for 6 prime values
while(x < infinite) {
boolean isPrime = true;
for(int i = 2; i <= x / 2; i++) {
if(x % i == 0) {
isPrime = false;
}
}
if(isPrime) {
System.out.println(x); // optional
ctr++;
if(ctr == nth) {
num = x;
break;
}
}
x++;
if(x == infinite) { // for bigger nth requested prime value
infinite++;
}
}
return num;
}
public static void main(String[] args) {
int ans = new progs().nthPrime(10001);
System.out.println("nth prime number is " + ans);
}
}