演算法之素數篩法
阿新 • • 發佈:2018-11-19
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
<1>方法一
//判斷是否是一個素數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;}
<2>方法二
#define MAXSIZE 10001int 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(Mark[i] == 1){ continue; } else{ //否則得到一個素數 prime[index++] = i; //標記該素數的倍數為非素數 for(int j = i*i;j < MAXSIZE;j += i){ Mark[j] = 1; } } } return index;}
<3>方法三
這種方法比較好理解,初始時,假設全部都是素數,當找到一個素數時,顯然這個素數乘上另外一個數之後都是合數
把這些合數都篩掉,即演算法名字的由來。但仔細分析能發現,這種方法會造成重複篩除合數,影響效率。
比如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的最小因子。
參考博文:點選開啟連結
習題練習:點選開啟連結