埃氏篩法的精髓在於,素數的倍數是合數。
如果我們把根號n前的質數的倍數找出來,那麼根號n和n之間的合數一定會被找出來,並且篩掉。
我們先證明一下為什麼只要把根號n前的質數找出來,並且把他在小於n的倍數都篩掉,就可以保證根號n和n之間沒有任何合數。我們利用反證法。
假設我們有一個 Q 他是一個合數, 他在根號n 和 n 之間。
我們把Q寫成 Q = pq,p和q是自然數,那麼就是說 p要大於根號n 才不會被篩掉,因為前面已經把所有倍數化掉了,如果當真存在沒有被化掉的,那麼他必然大於根號n,那麼我們來看看q,同樣的道理,所以Q 至少要大於n 才可以是沒有被篩掉。這不就和我們的前提矛盾了嗎?
如此一來,這種篩法的正確性就保證了。
那麼具體該如何實現呢?
我們可以從每個數自己的平方開始標記自己的倍數,因為根據上面的推敲,我們知道n前已經篩掉了。所以我們從n後面繼續篩。
代碼:
int Eratosthenes(int n){
int prime[n + 1];
memset(prime, 1, sizeof(prime));
prime[0] = prime[1] = 0;
int cnt = 0;
for(int i = 2; i * i<= n; i++){
if(prime){
for(int j = i * i; j <= n; j+=i){
prime[j] = 0;
}
}
}
for(int i = 2; i <= n; i++)if(prime[i])cnt++;
return cnt;
}
他的時間複雜度為 NloglogN
空間複雜度為N