三種素數篩法(普通篩法、埃氏篩法、尤拉篩法)
阿新 • • 發佈:2021-01-06
素數篩法
一般篩法:
一般篩法適用於單個元素的檢驗,就是簡單地對於一個元素 n 從2至 sqrt(n)進行檢驗能否整除,有一個就不是素數。
程式碼如下:
//原始篩選法->適用於單個元素的檢驗
bool isprime_A(int n)
{
for(int i = 2;i < sqrt(n);i++)
{
if(n % i == 0)
{
return false;
}
}
return true;
}
埃氏篩法
埃氏篩法利用了一個素數的倍數一定不是素數、任何一個合數可以表示成一個素數和另一個數乘積的性質。
對於一定的範圍,先假定它們都是質數,然後從2(顯然是素數)開始,先判斷如果是素數,把它在範圍內的倍數乘積都篩去(是合數),以此類推迴圈至 sqrt(n) 即可。
程式碼如下:
//埃拉託斯特尼(Eratosthenes)篩法->適用於一定範圍的元素的篩選
bool is_prime[1000];//布林陣列來標記是否為素數
int prime[1000] = {0}; //存放素數
int q = 0;
void isprime_B(int b) //要篩選素數的區間右端點
{
memset(is_prime,true,sizeof(is_prime));//先假設都為素數
for(int i = 2;i <= sqrt(b);i++)
{
if(is_prime[i])
{
prime[q++] = i;
for(int j = i*2;j <= b;j += i)//素數的倍數一定不是素數
{
is_prime[j] = false;
}
}
}
}
尤拉篩法
感覺尤拉篩法和埃氏篩法的原理類似…但是尤拉篩法更減少了沒有必要的計算,就是增加了處理:每一個被篩掉的數都必須是被它的最小質因子篩掉,為了保證這一點,增添了如下程式碼:
if(i % prime2[k] == 0)//確保是最小質因數
{
break;
}
為什麼這樣檢驗,想象一下,首先篩選的前提是:
也就是因子是按照遍歷的順序,是從小到大的素數。即:
而如果不break繼續篩選的話在篩選到滿足如下性質(即上述條件)的合數後:
會繼續篩選到一個更大的質數:
也滿足篩去:
但是它也可以表示為:
但是顯然prime[j]為它的最小素數,如果它被篩去那麼它是被prime[j+x]篩去的,而這並不是它的最小質數。
所以這個條件的限制是這麼個原因大概。
程式碼如下:
//尤拉篩法->適用於一定範圍的元素的篩選,時間複雜度O(n)
bool is_prime_Euler[1000];
int prime2[1000] = {0};
void isprime_C(int b)
{
int k = 0,j = 0;
memset(is_prime_Euler,true,sizeof(is_prime_Euler));
for(int i = 2;i <= b;i++)
{
if(is_prime_Euler[i])
{
prime2[j++] = i;
}
//接下來進行篩的操作
while(1)
{
if(i*prime2[k] > b)
{
break;
}
is_prime_Euler[i*prime2[k]] = false;//最小質因數的倍數一定不是素數
if(i % prime2[k] == 0)//確保是最小質因數
{
break;
}
k++;
}
k = 0;
}
}
可能在數理層面理解的還不夠深刻…希望大家能多指點。