[演算法]素數篩法
阿新 • • 發佈:2019-02-04
【方法一】
【程式碼一】
- //判斷是否是一個素數
- int IsPrime(int a){
- //0,1,負數都是非素數
- if(a <= 1){
- return 0;
- }
- //計算列舉上界,為防止double值帶來的精度損失,所以採用根號值取整後再加1,即寧願多列舉一個,也不願少列舉一個數
- int bound = (int)sqrt(a) + 1;
- for(int i = 2;i < bound;i++){
- //依次列舉這些數能否整除x,若能則必不是素數
-
if(a % i == 0){
- return 0;
- }
- }
- return 1;
- }
【方法二】
【程式碼二】
- #define MAXSIZE 10001
- int Mark[MAXSIZE];
- int prime[MAXSIZE];
- //判斷是否是一個素數 Mark 標記陣列 index 素數個數
- int Prime(){
- int index = 0;
- memset(Mark,0,sizeof(Mark));
- for(int i = 0;i < MAXSIZE;i++){
- //已被標記
-
if
- continue;
- }
- else{
- //否則得到一個素數
- prime[index++] = i;
- //標記該素數的倍數為非素數
- for(int j = i*i;j < MAXSIZE;j += i){
- Mark[j] = 1;
- }
- }
- }
- return index;
- }
【方法三】
這種方法比較好理解,初始時,假設全部都是素數,當找到一個素數時,顯然這個素數乘上另外一個數之後都是合數
把這些合數都篩掉,即演算法名字的由來。但仔細分析能發現,這種方法會造成重複篩除合數,影響效率。
比如10,在i=2的時候,k=2*15篩了一次;在i=5,k=5*6 的時候又篩了一次。所以,也就有了快速線性篩法。
【程式碼三】
- int Mark[MAXSIZE];
- int prime[MAXSIZE];
- //判斷是否是一個素數 Mark 標記陣列 index 素數個數
- int Prime(){
- int index = 0;
- memset(Mark,0,sizeof(Mark));
- for(int i = 2; i < MAXSIZE; i++)
- {
- //如果未標記則得到一個素數
- if(Mark[i] == 0){
- prime[index++] = i;
- }
- //標記目前得到的素數的i倍為非素數
- for(int j = 0; j < index && prime[j] * i < MAXSIZE; j++)
- {
- Mark[i * prime[j]] = 1;
- if(i % prime[j] == 0){
- break;
- }
- }
- }
- return index;
- }
程式碼中體現在:
if(i%prime[j]==0)break;
prime陣列 中的素數是遞增的,當 i 能整除 prime[j],那麼 i*prime[j+1] 這個合數肯定被 prime[j] 乘以某個數篩掉。
因為i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素數同理。所以不用篩下去了。
在滿足i%prme[j]==0這個條件之前以及第一次滿足改條件時,pr[j]必定是pr[j]*i的最小因子。