篩選法求素數

2021-08-19 08:16:26 字數 3110 閱讀 7686

以前稍微總結了下求素數的辦法。但是無奈效率都不高。

今天逛了很多關於求素數的部落格,於是總結了一下最終寫出了乙個篩選法的改進演算法。

篩選法:

(一般篩選法)這種方法比較好理解,初始時,假設全部都是素數,當找到乙個素數時,顯然這個素數乘上另外乙個數之後都是合數(i是素數,那麼i*1,i*2....i*n就是合數),把這些合數都篩掉,即演算法名字的由來。

但仔細分析能發現,這種方法會造成重複篩除合數,影響效率。比如10,在i=2的時候,k=2*15篩了一次;在i=5,k=5*6 的時候又篩了一次。所以,也就有了快速線性篩法。

[cpp]view plain

copy

print

? /*

一般篩選法

假設全部都是素數,當找到乙個素數時,

顯然這個素數乘上另外乙個數之後都是合數。

*/#include

#include

using

namespace std;  

const

int maxn = 100000;  

int isprime[maxn];  

void makeprime()  

}  }  }  

/*

一般篩選法

假設全部都是素數,當找到乙個素數時,

顯然這個素數乘上另外乙個數之後都是合數。

*/#include#includeusing namespace std;

const int maxn = 100000;

int isprime[maxn];

void makeprime()

} }}

線性篩選法的原理:

首先,先明確乙個條件,任何合數都能表示成一系列素數的積。

每乙個合數必有乙個最大的因子(不包括它本身),用這個因子把合數篩掉,還要另一種說啊(每個合數必有乙個最小素因子,用這個素因子篩掉合數,其實是一樣的),因為最大因子是唯一的,所以合數只會被它自己唯一的因子篩掉一次,把所有合數篩掉剩下的就全是素數了

證明略(參照:線性篩選法求素數原理】)

[cpp]view plain

copy

print

? /*

線性篩選法

每個合數必定有乙個最大的素因子。

所以每個合數只會被篩掉一次。

比一般篩選法效率要高一些。

*/#include

#include

using

namespace std;  

const

int maxn = 10000000;  

int isprime[maxn];//判斷是不是素數,1是,0不是。

int prime[maxn];//存放求得的素數。

int temp = 0;//當前已知素數的個數。

void makeprime()  

for (int j = 0; j < temp&&prime[j] * i < maxn; j++)//篩去合數。

}  }  }  

/*

線性篩選法

每個合數必定有乙個最大的素因子。

所以每個合數只會被篩掉一次。

比一般篩選法效率要高一些。

*/#include#includeusing namespace std;

const int maxn = 10000000;

int isprime[maxn];//判斷是不是素數,1是,0不是。

int prime[maxn];//存放求得的素數。

int temp = 0;//當前已知素數的個數。

void makeprime()

for (int j = 0; j < temp&&prime[j] * i < maxn; j++)//篩去合數。

}}}

然而這個方法時間複雜度和空間複雜度都不是很理想。於是出現了下面的方法。

改進的地方:

1,避開所有偶數(除2外,2單獨處理)。因為偶數至少有因子2。這樣迴圈就可以減少一半了。

2,乙個合數總可以化成若干個素數的乘積。

3,奇數x奇數(素數)=奇數。

4,每個奇數只會被篩一次。

[cpp]view plain

copy

print

? /*

只篩奇數的篩選法。

節省空間和時間一半。

*/#include

#include

using

namespace std;  

#define maxn 10000000

int prime[maxn/2];   

int isprime[maxn/2];//isprime[i]表示isprime[2*i+1],因為只處理奇數。

//【注:這裡的i為(2*i+1)】比如i=1時,表示的是2*1+1=3.同理i=2時,表示5,以此類推。

int temp = 0;  

void makeprime()  

long

long

int ans = i * 2 + 1;  

for (int j = 1; j < temp; j++)//遍歷素數表裡小於等於ans的素數,然後把他們乘積所得的奇合數篩掉

//j從1開始因為prime[0]=2;乘積是偶數所以沒必要從0開始。j除了0之外

//所以得prime[j]都是奇素數。奇素數*奇素數=奇偶數。而且乘的都是小於

//等於ans的素數所以不會出現重複篩選的情況。

if ((ans*prime[j]) % 2==0)//若是偶數則跳過,不處理。

isprime[i*((prime[j]-1)/2)] = 0;//找到奇合數,記錄下來。

//((prime[j]-1)/2)是將prime[j]還原為只存奇數的形式。

//如5,5都是素數。那5*5=25就是奇合數對應isprime[i]的

//i=(25-1)/2=12;標記prime[12]=0;即等於說明25不是素數。

//這樣做可以節省一半的空間。

}  }  

}  

篩選法求素數

題目 求100以內的所有素數。求素數的演算法常考,篩選法求素數不常見。定義長度為101的int陣列a 101 初始化為1。依次測試1到100的所有數字是否為素數。若i為合數,則a i 0。篩選完畢後,所有非0元素a i 所對應的數字i為素數。include using namespace std i...

篩選法求素數

篩選法求素數 質數 prime number 又稱素數。乙個 大於1的自然數 除了1和它本身外,不能被其他自然數 質數 整除,換句話說就是該數除了1和它本身以外不再有其他的因數 否則稱為合數 一 一般求素數的方法 乙個數n的因子不會超過n,但是如果我們知道數n的乙個因子a後,另乙個因子b b n a...

篩選法求素數

一 素數的定義 對於素數的定義,維基百科上給出如下一段話 素數指在大於1的自然數中,除了1和此整數自身外,無法被其他自然數整除的數。比1大但不是素數的數稱為合數。二 利用電腦程式,很容易就可以得到不太大的素數。以c語言為工具來描述常見的判斷素數的函式 int isprime int n 這個函式並不...