快速線性篩詳解

轉自:http://blog.csdn.net/dinosoft/article/details/5829550ios

 通常的線性篩法

首先先介紹通常的線性篩法求素數算法

void make_prime()  {        
    memset(prime, 1, sizeof(prime));  
    prime[0]=false;       
    prime[1]=false;       
    int N=31700;        
    for (int i=2;  i<N;  i++)           
      if (prime[i]) {            
        primes[++cnt ]=i;       
        for (int k=i*i; k<N; k+=i)          
            prime[k]=false;         
      }        
    return;  
}     

 

這種方法比較好理解,初始時,假設所有都是素數,當找到一個素數時,顯然這個素數乘上另一個數以後都是合數(注意上面的 i*i ,  比 i*2 要快點 ),把這些合數都篩掉,即算法名字的由來。spa

但仔細分析能發現,這種方法會形成重複篩除合數,影響效率。好比10,在i=2的時候,k=2*15篩了一次;在i=5,k=5*6 的時候又篩了一次。因此,也就有了快速線性篩法。.net

快速線性篩法

快速線性篩法沒有冗餘,不會重複篩除一個數,因此「幾乎」是線性的,雖然從代碼上分析,時間複雜度並非O(n)。先上代碼code

#include<iostream>   
using namespace std;      
const long N = 200000;     
long prime[N] = {0},num_prime = 0;      
int isNotPrime[N] = {1, 1};//先將0,1排除 
int main()      
{        
        for(long i = 2 ; i < N ; i ++)         
        {              
        if(! isNotPrime[i])     //isNotPrime==0            
            prime[num_prime ++]=i;//本身在前面打好了標記。 
        //關鍵處1           
/*i爲合數時也要參與循環*/       for(long j = 0 ; j < num_prime/*小於已經求出的質數個數*/ && i * prime[j]/*乘以其它質數,且質數比本身小或者是本身(已經求出來了),因此不可能重複*/ <  N ; j ++)  
            {                 
                isNotPrime[i * prime[j]] = 1;//乘以其它素數獲得的必定是合數,之因此不重複是由於質數間不等 
            if( !(i % prime[j] ) )  //關鍵處2 i%prime==0  根據「關鍵處2」的定義,當p1==prime[j] 的時候,
            //篩除就終止了(從最小質數開始因此本句話成立),            
                break;             
        }          
    }          
    return 0;
    //咱們能夠直觀地舉個例子。i=2*3*5*3,補大 

//此時能篩除 2*i ,不能篩除 3*i

//若是能篩除3*i 的話,當 i' 等於 i'=3*3*5 加小       時,篩除2*i' 就和前面重複了。(順序性) 
    
 }

 

 

先,先明確一個條件,任何合數都能表示成一系列素數的積。blog

 

無論 i 是不是素數,都會執行到「關鍵處1」,get

 

①若是 i 都是是素數的話,那簡單,一個大的素數 i 乘以不大於 i 的素數,這樣篩除的數跟以前的是不會重複的。篩出的數都是 N=p1*p2的形式, p1,p2之間不相等io

 

②若是 i 是合數,此時 i 能夠表示成遞增素數相乘 i=p1*p2*...*pn, pi都是素數(2<=i<=n),  pi<=pj  ( i<=j )class

p1是最小的係數。效率

根據「關鍵處2」的定義,當p1==prime[j] 的時候,篩除就終止了,也就是說,只能篩出不大於p1的質數*i。

 

咱們能夠直觀地舉個例子。i=2*3*5

此時能篩除 2*i ,不能篩除 3*i

若是能篩除3*i 的話,當 i' 等於 i'=3*3*5 時,篩除2*i' 就和前面重複了。

 

須要證實的東西:

  1. 一個數會不會被重複篩除。
  2. 合數確定會被幹掉。

根據上面紅字的條件,如今分析一個數會不會被重複篩除。

設這個數爲 x=p1*p2*...*pn, pi都是素數(1<=i<=n)  ,  pi<=pj ( i<=j ) 

當 i = 2 時,就是上面①的狀況,

當 i >2 時, 就是上面②的狀況, 對於 i ,第一個能知足篩除 x 的數  y 必然爲 y=p2*p3...*pn(p2能夠與p1相等或不等),並且知足條件的 y 有且只有一個。因此不會重複刪除。

 

證實合數確定會被幹掉? 用概括法吧。

 

 類比一個模型,好比說咱們要找出 n 中2個不一樣的數的全部組合 { i , j } ,1<=i<=n, 1<=j<=n,

咱們會這麼寫

for (i=1; i<n; ++i )

  for (j=i+1; j<=n; ++j)

   {

    /////

   }

咱們取 j=i+1 便能保證組合不會重複。快速篩法大概也是這個道理,不過這裏比較難理解,沒那麼直觀。

相關文章
相關標籤/搜索