素數篩選的三種方法

2021-08-22 10:32:54 字數 2352 閱讀 4243

第一種:剔除2 3 4 5 6 … … 的倍數

在i從2開始的增一變化過程中,剔除i的倍數即j*i(j是大於等於2的自然數,j的上限是問題規模m)

為了減少重複步驟,可以每當i遞增到等於第乙個沒有被剔除的(素)數時再剔除該數的倍數,

重複上述過程至i到達問題規模m的平方根+1

需要說明的三個問題:

假設迴圈到第n個數,如果該數沒有被剔除,那麼該數不能是前邊所有數的倍數,該數更不可能是後邊數的倍數,該

數就是素數。

如果該數是合數卻沒被剔除,那麼該數能分解為兩個小於該數的數的積的形式,而前邊剔除的數包含了所有小於該

數的數之間的積,這是矛盾的。

為什麼篩選迴圈的第一層只迴圈至問題規模m的平方根+1

因為,對於乙個數m,所有大於該數平方根的數的積已經大於該數了,再剔除下去只是多餘。

為什麼篩選迴圈的第二層只迴圈至max/i?

因為此時j*max/i就等於max,此時需要標記為錯誤的數已經到了問題的規模即max,沒有必要在標記比max大的值不

是素數,此外用來標記i*j不是素數的陣列只有max+1的容量,這樣做是向不是自己申請的記憶體空間裡寫資料,是危險的。

#include 

#include

#include

using

namespace

std;

const

int max=1000;

int main()

; for(i=2;i<=n;i++) //篩選迴圈

for(j=2;j<=max/i;j++)

a[j*i]=1;

for(i=2;i<=max;i++)

if(a[i]==0)

system("pause");

return

0;}

用a[i*j]來標記i*j不是素數,這乙個相對來說比較容易想到

第二種

#include

#include

#define max_p 500

int nlist[max_p] = ;

void calc()

printf("%5d", 2);

for (n=t=1;tif (nlist[t]) continue;

printf("%5d", (t<<1)+1);

if (++n==10)

}}int main(void)

**第三種**

#define max_n 1000

int a[max_n+1];

int p[max_n+1];

int ncount=0;

void init(int n) //線性篩法,不過在小範圍上(約n<1e7)不比上乙個方法快

for (int j=1,k; (j<=ncount) && (k=i*p[j])<=n; j++) //篩選迴圈

}}#include int main(void)

return0;}

這一種可以說是對前種演算法的直接變形

用a[k]=1來標記k不是素數

第一種是用篩選出來的正確的數(即素數)的倍數剔除合數

第二種是用2到n乘篩選出正確的數,即素數

如果你不以為然,我可以把for (n=3;n<=sq;n+=2)該為(n=3;nif (i%p[j] == 0) break;這一句新增進去是合理的

這句可解釋為當i第一次成為所挑選出來的正確的素數遞增序列的某個數(設為n)的整數倍時,就沒有必要讓i在去

乘遞增素數序列裡的比n大的素數,這又可以等價於 i乘比n大的合適的素數(設為max)可以等於比i大的整數(設

為j)乘比n小的素數(設為min),且這個j不是m的整數倍,即i*max=j*min;

又可以等價與j=i*max/min是乙個不是min倍數的整數,根據以前做因式分解的經驗乙個整數必然能分解為乙個遞增

的素數序列的積,如果我們假設i*max是這麼乙個整數,max是因數遞增序列中稍大的素數,則min只要是遞增序列中

小於max的素數,就能使j為整數,很顯然min包含於所有小於max的素數中,自然j是個整數,

又由於i不是max的倍數,max又不是min的倍數(如果是,max是素數嗎?)那麼i必然是min的倍數,又i是第一次成

為所挑選出來的正確的素數遞增序列的某個數(設為n)的整數倍,i必然不是min平方的倍數,即i/min不是min的倍

數,i/min

*max也不是min的倍數

至此就證明了if (i%p[j] == 0) break;這一句新增進去是合理的

三種素數篩選方法

第一種 剔除2 3 4 5 6 的倍數 在i從2開始的增一變化過程中,剔除i的倍數即j i j是大於等於2的自然數,j的上限是問題規模m 為了減少重複步驟,可以每當i遞增到等於第乙個沒有被剔除的 素 數時再剔除該數的倍數,重複上述過程至i到達問題規模m的平方根 1 需要說明的三個問題 假設迴圈到第n...

篩選素數的三種方法 包含尤拉篩

具體方法的介紹可以看下面詳細 有注釋 選出素數方法 include include include include include using namespace std const int maxn 1010 方法1 試除法 bool s prime int a return true 方法2 埃...

求素數的三種方法

具體篩法是 先把n個自然數按次序排列起來。1不是質數,也不是合數,要划去。第二個數2是質數留下來,而把2後面所有能被2整除的數都劃去。2後面第乙個沒劃去的數是3,把3留下,再把3後面所有能被3整除的數都劃去。3後面第乙個沒劃去的數是5,把5留下,再把5後面所有能被5整除的數都劃去。這樣一直做下去,就...