1. 程式人生 > >[演算法]素數篩法

[演算法]素數篩法

【方法一】


【程式碼一】

  1. //判斷是否是一個素數
  2. int IsPrime(int a){  
  3.     //0,1,負數都是非素數
  4.     if(a <= 1){  
  5.         return 0;  
  6.     }  
  7.     //計算列舉上界,為防止double值帶來的精度損失,所以採用根號值取整後再加1,即寧願多列舉一個,也不願少列舉一個數
  8.     int bound = (int)sqrt(a) + 1;  
  9.     for(int i = 2;i < bound;i++){  
  10.         //依次列舉這些數能否整除x,若能則必不是素數
  11.         if(a % i == 0){  
  12.             return 0;  
  13.         }  
  14.     }  
  15.     return 1;  
  16. }  


【方法二】


【程式碼二】

  1. #define MAXSIZE 10001
  2. int Mark[MAXSIZE];  
  3. int prime[MAXSIZE];  
  4. //判斷是否是一個素數  Mark 標記陣列 index 素數個數
  5. int Prime(){  
  6.     int index = 0;  
  7.     memset(Mark,0,sizeof(Mark));  
  8.     for(int i = 0;i < MAXSIZE;i++){  
  9.         //已被標記
  10.         if
    (Mark[i] == 1){  
  11.             continue;  
  12.         }  
  13.         else{  
  14.             //否則得到一個素數
  15.             prime[index++] = i;  
  16.             //標記該素數的倍數為非素數
  17.             for(int j = i*i;j < MAXSIZE;j += i){  
  18.                 Mark[j] = 1;  
  19.             }  
  20.         }  
  21.     }  
  22.     return index;  
  23. }  

【方法三】

這種方法比較好理解,初始時,假設全部都是素數,當找到一個素數時,顯然這個素數乘上另外一個數之後都是合數

把這些合數都篩掉,即演算法名字的由來。但仔細分析能發現,這種方法會造成重複篩除合數,影響效率。

比如10,在i=2的時候,k=2*15篩了一次;在i=5,k=5*6 的時候又篩了一次。所以,也就有了快速線性篩法。

【程式碼三】

  1. int Mark[MAXSIZE];  
  2. int prime[MAXSIZE];  
  3. //判斷是否是一個素數  Mark 標記陣列 index 素數個數
  4. int Prime(){  
  5.     int index = 0;  
  6.     memset(Mark,0,sizeof(Mark));  
  7.     for(int i = 2; i < MAXSIZE; i++)  
  8.     {  
  9.         //如果未標記則得到一個素數
  10.         if(Mark[i] == 0){  
  11.             prime[index++] = i;  
  12.         }  
  13.         //標記目前得到的素數的i倍為非素數
  14.         for(int j = 0; j < index && prime[j] * i < MAXSIZE; j++)  
  15.         {  
  16.             Mark[i * prime[j]] = 1;  
  17.             if(i % prime[j] == 0){  
  18.                 break;  
  19.             }  
  20.         }  
  21.     }  
  22.     return index;  
  23. }  
利用了每個合數必有一個最小素因子。每個合數僅被它的最小素因子篩去正好一次。所以為線性時間。
程式碼中體現在:
if(i%prime[j]==0)break;
prime陣列 中的素數是遞增的,當 i 能整除 prime[j],那麼 i*prime[j+1] 這個合數肯定被 prime[j] 乘以某個數篩掉。
因為i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素數同理。所以不用篩下去了。

在滿足i%prme[j]==0這個條件之前以及第一次滿足改條件時,pr[j]必定是pr[j]*i的最小因子。