如何最优雅地实现这个函数:
ArrayList generatePrimes(int n)
这个函数生成前{{n}}个质数(编辑:其中{{n>1}}),所以
generatePrimes(5)
将返回一个ArrayList
,其中包含{2, 3, 5, 7, 11}
。(我是用C#来实现的,但我也可以接受Java - 或者其他类似的语言(不包括Haskell)的实现)。我知道如何编写此函数,但昨晚我写的结果并不如我希望的那么好。以下是我的代码:ArrayList generatePrimes(int toGenerate)
{
ArrayList primes = new ArrayList();
primes.Add(2);
primes.Add(3);
while (primes.Count < toGenerate)
{
int nextPrime = (int)(primes[primes.Count - 1]) + 2;
while (true)
{
bool isPrime = true;
foreach (int n in primes)
{
if (nextPrime % n == 0)
{
isPrime = false;
break;
}
}
if (isPrime)
{
break;
}
else
{
nextPrime += 2;
}
}
primes.Add(nextPrime);
}
return primes;
}
我对速度不是太关心,尽管我不希望它明显低效。我不介意使用哪种方法(朴素的还是筛法的还是其他什么的),但我希望它相当简短,并且很明显它是如何工作的。
编辑:感谢所有回复我的人,尽管许多人没有回答我的实际问题。再次强调,我想要一个好的、干净的代码片段来生成质数列表。我已经知道了很多不同的方法,但我往往编写的代码并不像它本应该那样清晰易懂。在这个主题中,有几个好的选择被提出:
- 一个更好的版本,与我最初拥有的相似(Peter Smit、jmservera和Rekreativc)
- 一个非常干净的埃拉托色尼筛法实现(starblue)
- 使用Java的
BigInteger
和nextProbablePrime
来编写非常简单的代码,尽管我无法想象它特别高效(dfa) - 使用LINQ来懒惰地生成质数列表(Maghis)
- 在文本文件中放置大量质数,并在必要时读取它们(darin)
编辑 2: 我已经在 C# 中实现了这里给出的一些方法,还有另一种方法没有在这里提到。它们都可以有效地找到前n个质数(我有一个不错的方法来找到提供给筛子的限制)。
nubBy (((>1).).gcd) [2..]
。它只保留自然数中从2开始的非重复数字,同时将任何与先前找到的数字之一的gcd大于1的数字视为重复。它非常低效,产生的质数数量平方级增长。但它很优雅。 - Will Nessimport Data.List.Ordered ; let { _Y g = g (_Y g) ; primes = 2 : _Y( (3:) . minus [5,7..] . unionAll . map (\p-> [p*p, p*p+p*2..]) ) }
当然,这完全基于个人观点。 - Will Ness