這個問題可以有兩種解法:一種是用「篩子法」,另一種是從 2→n 逐一檢測出質數。如果要了解「篩法」,請看另一篇文章《求質數 之 篩法 》。
現在來介紹第二種方法。用這種方法,最先想到的就是讓從2→n逐一檢查。如果是就顯示出來,如果不是,就繼續檢查下乙個直到超出範圍 n。這是正確的做法,但效率卻不高。當然,2 是質數,那麼 2 的倍數就不是質數,如果令 i 從 2→ n,就很冤枉地測試了 4、6、8……這些數?所以第一點改建就是只測試 2 與所有的奇數就足夠了。同理,3 是質數,但6、9、12……這些 3 的倍數卻不是,因此,如果能夠把 2 與 3 的倍數跳過去而不測試,任意連續的 6 個數中,就只會測試 2 個而已。以6n, 6n+1, 6n+2, 6n+3, 6n+4, 6n+5 為例,6n, 6n+2, 6n+4 是偶數,又 6n+3 是 3 的倍數,所以如果 2 與 3 的倍數都不理會,只要測試的數就只留下6n+1和6n+5而已了,因而工作量只是前面想法的 2/6 = 1/3,應該用這個方法程式設計。
還有個問題,就是如果判斷乙個數 i 是否為素數。按素數的定義,也就是只有 1 與本身可以整除,所以可以用 2→ i-1 去除 i,如果都除不盡,i 就是素數。觀點對,但卻與上一點一樣的笨拙。當 i>2 時,有哪乙個數可以被 i-1 除盡的?沒有!為什麼?如果 i 不是質數,那麼 i=a×b,此地 a 與 b 既不是 i 又不是 1;正因為 a>1,a 至少為 2,因此 b 最多也是 i/2 而已,去除 i 的數用不著是 2→ i-1,而用 2→ i/2 就可以了。不但如此,因為 i=a×b,a 與 b 不能大於 sqrt(i),為什麼呢?如果 a>sqrt(i),b>sqrt(i),於是 a×b > sqrt(i)*sqrt(i) = i,因此就都不能整除i了。如果i不是質數,它的因子最大就是 sqrt(i);換言之,用 2→ sqrt(i)去檢驗就行了。
但是,用 2→ sqrt(i) 去檢驗也是浪費。就像前面一樣,2 除不盡,2 的倍數也除不盡;同理,3 除不盡,3 的倍數也除不盡……最理想的方法就是用質數去除i。
但問題是這些素數從何而來?這比較簡單,可以準備乙個陣列 prime,用來存放找到的素數,一開始它裡面有 2、3、5。檢查的時候,就用 prime 中小於 sqrt(i)的數去除 i 即可,如果都除不盡,i 就是素數,把它放如 prime 中,因此 prime 中的素數會越來越多,直到滿足個數為止!
不妨用這段說明來編寫這個程式,但是程式設計的時候會有兩個小問題:
如果只檢查 6n+1 和 6n+5 ?不難發現,它們的距離是4、2、4、2……所以,可以先定義乙個變數 gab=4,然後 gab=6-gab;
比較是不能用 sqrt(i),因為它不精確。舉個例子,i=121,在數學上,sqrt(i) 自然是 11,但計算機裡的結果可能是 10.9999999,於是去除的數就是 2、3、5、7,而不含 11,因此 121 就變成質數了。解決這個問題的方法很簡單,不要用開方,用平方即可。例如,如果 p*p<=i,則就用 p 去除 i。而且它的效率比開方高。
[cpp]view plain
copy
print?
#include
#include
intcreat_prime(
intp,
intn,
inttotal)
} return
total;
} int
main(
void
) ;
inttotal = 3;
/* 找到素數的個數 */
intn = 200000;
/* 要查詢的範圍(>=6) */
inti;
total = creat_prime ( prime, n, total );
for(i = 0; i < total; i++)
putchar ( '/n'
);
return
exit_success;
}
求質數之Eratosthenes篩選法(C 版)
eratosthenes計算小於100000的素數質數 時間複雜度是o nloglogn 演算法原理 乙個合數總是可以分解成若干個質數的乘積,那麼如果把質數 最初只知道2是質數 的倍數都去掉,那麼剩下的就是質數了。二 步驟 1 先把1刪除 1既不是質數也不是合數 2 讀取佇列中當前最小的數2,然後把...
雜湊表除留取餘法的桶個數為什麼是質數
可先科普下質數的概念 質數,也就是素數,就是指乙個大於1的自然數,約數 因數 只有1和它自己,否則叫合數。除留取餘,就是雜湊函式將關鍵字被某個不大於雜湊表長m的數p除后所得餘數為雜湊位址。這是最常用 也最簡單的構造雜湊函式的方法。當然,也可以對關鍵字直接取模,也可以摺疊 平方取中等運算後取模。那麼問...
Fibonacci數列求餘 C語言
fibonacci數列求餘 c語言 問題描述 fibonacci數列的遞推公式為 fn fn 1 fn 2,其中f1 f2 1。當n比較大時,fn也非常大,現在我們想知道,fn除以10007的餘數是多少。輸入格式 輸入包含乙個整數n。輸出格式 輸出一行,包含乙個整數,表示fn除以10007的餘數。說...