筛选质数

关于怎么判断一个数 n 是否是质数,最简单的方法是枚举 2 到 n−1,判断是否是 n 的约数。如果是, n 肯定不是一个质数。再仔细想想,如果 a 是 n 的一个约数,那么必然有一个b 满足 ab = n,a≤√​n​​​ 和 b≤√​n​​​ 中必然有一个成立,因为如果a>√​n​​​ 并且 b>√​n​​​,那么 ab>n,和 ab = n 矛盾。因此如果 n 是一个合数,那么我们只需要枚举到 √​n​​​ 就一定能找到 n的一个约数。否则,n 肯定是一个质数。下面是代码:

int is_prime(int n)  
{  
   for(int i = 2; i * i <= m; i++)  
      if(n % i == 0)  
         return 0;//不是质数   
   return 1;//是质数         
}  

更多的时候,需要预处理出一段区间上的质数,如果按照之前的方法一个一个判断,时间上肯定会承受不了。于是提出了一种预处理 1 到 N 上质数的算法,称为 Eratosthenes 筛选。

素数筛选算法的基本思想是我们先假设 2 到 N 所有数都是素数。我们从 2 开始扫描,对于一个数 i,可以得到 2i, 3i ……ki 都不是素数,因为这些数都有 i 这个因子,表示这些数不是素数,一直枚举到 N。对于每一个合数,它至少会被它的一个因子枚举到,所以可能证明这个算法的正确性。接下来分析时间复杂度,对于每个 i,枚举的次数为 n / i​​,所以总时间复杂度为 N/2 + N/3 + … + N/N = O(NlgN) 。

下面是代码:

for(int i = 2; i <= n; i++)  
{  
   is_prime[i] = 1;   
}  
for(int i = 2; i <= n; i++)  
{  
   for(int j = i * 2; j <= n; j += i)  
      {  
         is_prime[j] = 0;  
      }  
}  

上面的代码便筛选出来了 n 以内的素数,如果 is_prime[i] = 1,i 是素数,否则 i 是合数。上面的代码还可以优化。第一是基于每个合数必然有一个质因子,所以我们可以只用质数来筛选,第二是 j 的初始条件可以写成 j = i * i,因为比如 j = i * k( k < i), 那么 j 肯定被k 筛选掉了。第三是可以只用√​n​​​ 之前的质数去筛选。优化之后的时间复杂度比O(NlgN)还要低得多。优化以后的代码如下:

for(int i = 2; i <= n; i++)  
{  
   is_prime[i] = 1;  
}  
for(int i = 2; i * i <= n; i++)  
{  
   if(is_prime[i])  
   {  
         for(int j = i * i; j <= n; j += i)  
      {  
         is_prime[j] = 0;  
      }  
   }  
}  

你可能感兴趣的:(筛选质数)