1. 程式人生 > 其它 >一一般篩法 + 埃式篩法 + 線性篩法

一一般篩法 + 埃式篩法 + 線性篩法

我們如何計算從1~n一共有多少個質數呢,我們就要考慮一種篩法,用已知的數把確定的那些不會是質數的數全部篩掉!

 

我們先介紹第一種一般篩法:

void get_primes2(){
for(int i=2;i<=n;i++){

if(!st[i]) primes[cnt++]=i;//把素數存起來
for(int j=i;j<=n;j+=i){//不管是合數還是質數,都用來篩掉後面它的倍數
st[j]=true;
}
}
}

 

分析:第一種篩法就是無論是合數還是質數都可以用來把後面那些不可能是質數的數給全部ban掉;

比較麻煩,所以時間複雜度是O(nlogn)

 

第二種篩法:埃式篩法

void get_primes1(){
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++]=i;
for(int j=i;j<=n;j+=i) st[j]=true;//可以用質數就把所有的合數都篩掉;
}
}
}

 

分析:這個篩法是一位叫做Eratosthenes的人發明的篩法,不是因為這個發明的人是埃及人;

這個篩法的高明之處在於我們不再利用合數去篩掉別的數字了,因為合數本身就能被質數篩掉,所以這個合數去篩的那些數肯定會被質數提前篩掉,這樣就少去了很多重複的過程;

時間複雜度是O(nloglogn),已經很快了,但是如果遇到10^7的數量級就會爆時間,所以就需要引出我們接下來的線性篩法!

 

第三種篩法:線性篩法

void get_primes(int n){
for(int i = 2;i<=n;i++){
if(!st[i]) primes[cnt++] = i;
for(int j = 0;primes[j]<=n/i;j++){
st[primes[j]*i] = true;
if(i%primes[j] == 0) break;
}
}
cout << cnt << '\n';


}

 

分析:這個方法好在哪兒呢,首先可以看到我們把所有的質數都放入到primes數組裡面,我用的相當於是最小質因數去篩掉那些合數,當我們看到這裡我們可以發現對應每個質數i時,primes陣列遞增,只可能是primes[j]^2,是因為primes[j]^2前面的數都已經被篩除乾淨了,最小的質因數就是primes[j],比如10 = 2*5;我們使用2去篩掉的10,因為我用5去篩只能篩掉25,30,35,這些數字了,所以線性篩法的點在於用最小質因數篩,避免了質數重複篩;

時間複雜度是O(n)的,非常快!!!