該問題出自《c語言名題精選百則技巧篇》
從2開始,先刪除2*2, 2*2*2,2*2*2*2,...接著刪除2*3, 2*2*3 ,2*2*2*3,...(3並沒有被刪除),再刪除2*5, 2*2*5, 2*2*2*5,...;然後刪除2*7, 2*2*7, 2*2*2*7,...;然後是2*9, 2*2*9, 2*2*2*9,...。當發現p是乙個質數的時候,先刪除p*p, p*p*p, p*p*p*p,,,,。因為p是個質數,p*p, p*p*p, p*p*p*p,,,,不可能被其他整數整除,所以在此之前不可能被整除,接著去找比p大的,但沒被刪除的數,因此,q*(p*p*p*...*p)(i個p)在此之前也沒有被刪除過。
如果找出2~n的所有質數,p*p<=n。刪除的工作可以寫成:
for(p=2;p*p<=n;next(p))
for(q=p;p*q<=n;next(q))
for(m=p*q;m<=n;m=p*m)
remove(m)
next(p)用來找比p大但還未被刪除的下乙個數,它一定是質數,如果它不是質數,在比p小的數進行搜尋的時候,就已經把它給刪除了;找到p以後,令q從p起,刪除pq, p*p*q, p*p*p*q,....之後再去找出下乙個沒有被刪除的數做q,如此迴圈。
用乙個雙向連線序列(double linked list),在開始的時候第i個元素的previous[i]是i-1,next(i)是i+1,previous(2)沒有上乙個,next(n)沒有下乙個,用null表示。用乙個函式來初始化這兩個陣列。
比如n=20。
previous =
next =
要刪除某乙個數,例如m,也很簡單,只要m的上乙個元素(previous[m])的下乙個指標(next[previous[m]]))指向m的下乙個元素(next[m]),再將m的下乙個元素的上乙個指標(previous[next[m]])指向m的上乙個元素(previous[m])就可以了,這個叫做remove(m).
比如要刪除4,6,8,10,12,14,16,18,20這些元素,previous和next變成
previous =
next =
再刪除9和15
previous =
next =
從next裡取出質數,從2開始i=2,輸出2,下乙個i=next[i] = 3,輸出3;下乙個i = next[3] = 5,輸出5;下乙個i=next[5] = 7,輸出7;下乙個i=next[7] = 11, 輸出11;下乙個i = next[11] = 13,輸出13;下乙個i=next[13] = 17,輸出17;下乙個i=next[17] = 19,輸出19;下乙個i=next[19] = null,結束。
程式如下:
#include #include #define maxsize 400
#define next(x) x=next[x]
#define remove(x)
#define initial(n)
int main(int argc,char *argv)
printf("\n\nthere are %ld prime numbers in total",count);
getchar();
return 0;
}
執行結果
質數線性篩法 O n
埃氏篩法o nloglogn 仍會重複標記合數 such as i 2時 12 2 6,先會被 2 標記已是合數 i 3時 12 3 4,又被標記了一次 我們在生成乙個需要標記的合數時,每次只向現有的數中乘上乙個質因子,並且讓它是所生成合數的最小質因子 code include include us...
線性篩質數,線性求尤拉
本篇前半部分講線性篩質數,也叫尤拉篩,後半篇講解線性求尤拉函式。我們有一種篩質數的辦法,就是列舉每個質數,然後把這個質數的倍數都篩掉,這個做法比較簡單,在這裡不做過多介紹。尤拉篩就是在這個方法的基礎上,使得每個合數只會被它最小的那個質因子篩掉,保證了複雜度是線性的 memset isprime,1,...
篩法求素數 線性篩法求素數
2021年更新版 篩法求素數 線性篩法求素數 要理解篩法求素數首先要知道乙個定理,整數唯一分解定理 任意大於等於2的正整數都有且只有一種方式寫出其質因子的乘積表示式。a p1p2p3p4 pn pi是素數且pi pj eg 2 2 4 22 12 223 36 2233 也就是說任意乙個合數都能分成...