质数又称素数。指在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。
一、判断一个数是否为质数
首先根据定义,最简单的判断一个数n是否为质数的方法,就是从2开始对小于n的所有数,依次判断是否能整除n,若都不能整除就是质数。
bool IsPrime(int n)
{
if(n == 1)
return false;
for(int i = 2; i < n; i++)
if(n % i ==0)
return false;
return true;
}
我们再稍微改进一下,我们可以先判断一下2能不能整除n,然后2以上的偶数就不需要再判断了,因为2不能整除n那么含有因子2的数肯定也不能整除n。再者,我们根本不需要循环到n,若两个数的乘积为n,那么肯定有一个因子是小于sqrt(n)的,所以,循环的上限可以取sqrt(n)。于是就有:
bool IsPrime(int n)
{
if(n == 2)
return true;
if(n == 1 || (n & 1))
return false;
int k = (int)sqrt(n);
for(int i = 3; i <= k; i += 2)
if(n % i == 0)
return false;
return true;
}
上面是过滤掉了2的倍数,计算量变为原来的二分之一,我们也可以把3的倍数过滤掉,也就是只判断3是否能整除n,其它3的倍数就不需要判断了,计算量就可以变为原来的三分之一。也就是只剩6*k+1和6*k+5(k为整数)这些数,因为其他数都含有因子2或3,n若不能被2或3整除,那么n也不能被6*k,6*k+2,6*k+3,6*k+4这些数整除,就不需要判断这些数能否整除n了,这样又减少了判断量。
bool IsPrime(int n)
{
if((n == 2) || (n == 3))
return true;
if((n == 1) || ((n & 1) == 0) || ((n % 3) ==0))
return false;
int k = (int)sqrt(n);
int step = 4;
for(int i = 5; i <= k; i += step)
{
if(n % i == 0)
return false;
step = 6 - step;
}
return true;
}
二、找出区间内的所有质数
要求区间内的所有质数,首先可以用以上判断单个质数的方法挨个寻找,但是太慢了。。。
这类问题主要的就是筛选法了。筛法求质数的主要思想就是,从小到大,当判断完一个数K是否为质数后,把后面的所有的K的倍数(含因子K)都去掉。
#define N 1000000
bool isPrime[N];
int i;
memset(isPrime, true, sizeof(isPrime));
isPrime[1] = false;
//筛掉大于2的偶数
for(i = 4; i < N; i += 2)
isPrime[i] = false;
int bound = sqrt(N);
//用sqrt(N)以内的质数去筛掉后面含有质数因子的元素
for(i = 3; i <= bound; i += 2)
{
//从3开始的奇数,如果是质数就去筛掉以自己为因子的元素,不是质数跳过
if(false == isPrime[i])
continue;
int step = i << 1;
//i为质数,则从i*i开始筛,以2*i为步长(因为偶数已被筛掉,小于i*i的非质数,已被小于i的质数筛掉)
for(int j = i * i ; j < N ; j += step) //含有质数因子i,筛掉
isPrime[j] = false;
}
若求两个大数之间的质数,也可以用筛法
如求N1和N2之间的质数1000000000 <= N1 < N2 < 2^32 and 1 < N2 – N1 < 1000000
bool isPrime[1000000];
int prime[70000]; //保存小于65536的质数(可以筛unsigned int范围内的数),筛法求出
int primeCnt; //小于65536的质数个数
int i, j;
/*
求小于65536的质数,保存在prime数组中
*/
int N1 = 100000000;
int N2 = 101000000;
int D = N2 - N1;
memset(isPrime, true, sizeof(isPrime));
for(i = 0; i < primeCnt; i++)
{
int k = N2 % prime[i];
//可知 N2-k 含质因子prime[i],不是质数,N2 - k - x*prime[i](x为整数)都不是质数数,筛掉
int step = prime[i];
int j = D - k;
// N2 - k 对应于数组下标 D - k, N2 - k - x * prime[i] 对应于数组下标 j - x * prime[i];
while(j >= 0)
{
isPrime[j] = false; //isPrime[j] 代表 N1 + j 是否是质数
j -= step;
}
}