找质数算法
我们知道,对于一个给定的数判断该数是不是质数,很简单,只需要对其开根号,然后循环取模即可:
public bool IsPrime(int number)
{
if (number < 2)
{
return true;
}
else
{
for (int i = 2; i <= Math.Sqrt(number); i++)
{
if (number % i == 0)
{
return false;
}
}
}
return true;
}
{
if (number < 2)
{
return true;
}
else
{
for (int i = 2; i <= Math.Sqrt(number); i++)
{
if (number % i == 0)
{
return false;
}
}
}
return true;
}
但是,对于一个给定的整数,怎样计算出小于该整数的所有素数呢?比较常见的是采用Sieve of Eratosthenes算法,它的基本思想是这样:
由于一个合数总是可以分解成若干个质数的乘积,那么如果把质数(最初只知道2是质数)的倍数都去掉,那么剩下的就是质数了。例如要查找100以内的质数,首先2是质数,把2的倍数去掉;此时3没有被去掉,可认为是质数,所以把3的倍数去掉;再到5,再到7,7之后呢,因为8,9,10刚才都被去掉了,而100以内的任意合数肯定都有一个因子小于10(100的开方,可参考前面判断质数的算法),所以,去掉,2,3,5,7的倍数后剩下的都是质数了。
具体实现,我们通过设置两个数组,一个bool数组crossedOut,用来标识对应下标的数字是不是质数,如果i是质数,crossedOut[i]=false,否则crossedOut[i]=true。那么划掉i可以表示成crossedOut[i]=true。还有一个int型数组是result,用来存储符合要求的素数。具体实现如下:
public class PrimeGenerator
{
private static bool[] crossedOut;
private static int[] result;
public static int[] GeneratePrimeNumbers(int maxValue)
{
if (maxValue < 2)
{
return new int[0];
}
else
{
UncrossIntegersUpTo(maxValue);
CrossOutMultiples();
PutUncrossedIntegersIntoResult();
return result;
}
}
private static void UncrossIntegersUpTo(int maxValue)
{
crossedOut = new bool[maxValue + 1];
for (int i = 2; i < crossedOut.Length; i++)
{
crossedOut[i] = false;
}
}
private static void PutUncrossedIntegersIntoResult()
{
result = new int[NumberOfUncrossedIntegers()];
for (int j = 0, i = 2; i < crossedOut.Length; i++)
{
if(NotCrossed(i))
{
result[j++] = i;
}
}
}
private static int NumberOfUncrossedIntegers()
{
int count = 0;
for (int i = 2; i < crossedOut.Length; i++)
{
if (NotCrossed(i))
{
count++;
}
}
return count;
}
private static void CrossOutMultiples()
{
int limit = DetermineIterationLimit();
for (int i = 2; i <= limit; i++)
{
if (NotCrossed(i))
{
CrossOutputMultiplesOf(i);
}
}
}
private static int DetermineIterationLimit()
{
double iterationLimit = Math.Sqrt(crossedOut.Length);
return (int)iterationLimit;
}
private static void CrossOutputMultiplesOf(int i)
{
for (int multiple = 2 * i; multiple < crossedOut.Length; multiple += i)
{
crossedOut[multiple] = true;
}
}
private static bool NotCrossed(int i)
{
return crossedOut[i] == false;
}
}
{
private static bool[] crossedOut;
private static int[] result;
public static int[] GeneratePrimeNumbers(int maxValue)
{
if (maxValue < 2)
{
return new int[0];
}
else
{
UncrossIntegersUpTo(maxValue);
CrossOutMultiples();
PutUncrossedIntegersIntoResult();
return result;
}
}
private static void UncrossIntegersUpTo(int maxValue)
{
crossedOut = new bool[maxValue + 1];
for (int i = 2; i < crossedOut.Length; i++)
{
crossedOut[i] = false;
}
}
private static void PutUncrossedIntegersIntoResult()
{
result = new int[NumberOfUncrossedIntegers()];
for (int j = 0, i = 2; i < crossedOut.Length; i++)
{
if(NotCrossed(i))
{
result[j++] = i;
}
}
}
private static int NumberOfUncrossedIntegers()
{
int count = 0;
for (int i = 2; i < crossedOut.Length; i++)
{
if (NotCrossed(i))
{
count++;
}
}
return count;
}
private static void CrossOutMultiples()
{
int limit = DetermineIterationLimit();
for (int i = 2; i <= limit; i++)
{
if (NotCrossed(i))
{
CrossOutputMultiplesOf(i);
}
}
}
private static int DetermineIterationLimit()
{
double iterationLimit = Math.Sqrt(crossedOut.Length);
return (int)iterationLimit;
}
private static void CrossOutputMultiplesOf(int i)
{
for (int multiple = 2 * i; multiple < crossedOut.Length; multiple += i)
{
crossedOut[multiple] = true;
}
}
private static bool NotCrossed(int i)
{
return crossedOut[i] == false;
}
}