素數演算法總結

2021-07-10 07:26:16 字數 2602 閱讀 8746

素數又叫質數(prime number),有無限個,只能能被1和自身整除的自然數.

由於這句話,在我們求給定範圍n以內的素數的時候,我們通常採用的是下面這種演算法:

#include 

intmain(void)

}if (flag)

printf("%d\n", i);

}return (0);

}

上面是非常低效的,低效的原因在於我們遍歷每個數字的時候都會對同樣的數字進行求餘操作.

什麼意思呢?

舉例來說:

當n = 10的時

我們要遍歷的數字是:

3 4 5 6 7 8 9 10

遍歷時,

每個數字都會都2進行整除運算.

3 % 2, 4 % 2, 5 % 2, 6 % 2, 7 % 2, 8 % 2, 9 % 2, 10 % 2.

反向思維一下,如果我們發現乙個數字是2的倍數,那麼這個數字就能夠被2整除,那麼他肯定就不是素數.

以此類推

每次重複的操作還有對3, 4, 5, 6 …. n-1;

因此可以肯定的是,如果乙個數是莫個數的倍數,這個數就可以肯定不是素數了.

數學上有如下的算數定理:

乙個自然數,要麼本身是乙個質數,要麼可以寫成一系列質數的乘積.

由此可知,是質數乘積的數肯定不是質數.

在此基礎上,古希臘數學家埃拉託斯特尼所提出了一種快速檢定素數的演算法:(也就是我們上面描述的內容)

要得到自然數n以內的全部素數,必須把不大於根號n 的所有素數的倍數剔除,剩下的就是素數。

簡單描述一下,求10以內的素數:

2 3 4 5 6 7 8 9 10

劃掉2的倍數(2是素數) :剩下的還有

2 3 5 7 9

劃掉3的倍數

2 3 5 7

劃掉5的倍數,由於根號10 是小於5的,所以不用劃5的倍數;

最終輸出結果

2 3 5 7;

由此我們得到如下演算法:

#include 

#include

#define maxsize 1000001

/* *採用eratosthenes篩法, 給定範圍n以內的素,

*劃掉根號n以內的素數的倍數的數, 剩下的都是素數.

*prime陣列儲存求得的素數

*如果為0,則是素數, 反之則不是

*被劃掉的數字我們用1表示.

*/char prime[maxsize];

void

initprime()

intmain(void)

return(0);

}

記憶體迴圈每次增加i的倍數,一般我們會從i的2倍開始;

但是通過看下面這張我們可以看出,其實j不用從2的倍數開始,因為2 * i已經在劃掉2的倍數的時候被劃掉了,同理3*i也已經在3的倍數裡面被劃掉了,

也就是說直到i * i ,之前所有比i小的倍數都已經被比 i小的素數的倍數 劃掉了(表達得不是很清楚 -.- ,看了應該好懂一些 ).請看下圖:

i表示素數,j表示素數的倍數的位置,紅色方框表示我們內層迴圈j( i * i) 開始的位置.

從圖中我們可以看出,

比i的小的倍數都在遍歷之前被劃掉了.

比如當i = 5的時候,

5* 2(遍歷素數2的倍數的時候),

5 * 3(遍歷素數3的倍數的時候),

5 * 4(這個不是素數,我們稍後討論),

都已經被劃掉了,所以不用再重複劃掉了.

由此我們可以看出,j從i*i開始是合理的,而且隨著i的增加,我們所需要遍歷的比i小的倍數會逐漸增加,採用從i*i開始遍歷,又進一步縮減了我們遍歷的時間.

細心的同學可能已經看到,從i*i的倍數往下遍歷的時候,有很位置我們也是已經劃過了,

比如:

在5*6的位置,

又因為5 * 6 = 3 * 10 = 3 * 2 * 5 = 30的位置,也就是2 * 3 * 5;

就是說在我們遍歷2*15時,30我們劃掉過一次.

在遍歷3 * 10的時候,30的位置又被我們劃掉過一次.

那麼從i*i開始以後的那個位置是肯定不會被前面的素數的倍數劃掉的呢?

先從3開始看:

3 * 4, 4肯定會被劃掉(因為2 * 2)

3 * 5不會被劃掉.

3 * 6被劃掉.

3 * 7不會.

3 * 8被劃掉.

3 * 9被劃掉.

也就是前面沒有出現過的素數的倍數,肯定不會被劃掉,因此在遍歷的時候,我們在尋找素數倍數的時候,只需要尋找素數的素數倍數,但是這裡會出現乙個問題,因為我們本身就是在查詢素數,那麼我們怎麼知道乙個素數的倍數呢?

因為所有2的倍數肯定不是奇數,所以我們不用儲存奇數字,我們假設我們陣列裡面儲存的全部都是奇數,

數論演算法總結 素數

1.如果給定乙個數n,要你計算小於n的素數的個數,如果n足夠大,那麼 素數的個數等價於x ln x 如下 include include includeusing namespace std 這是判斷素數個數的位數 void pr int n cout static cast log10 k log...

素數判定總結

1.對於百萬級別,判斷單個數是否為素數,用埃拉託斯尼斯篩法打乙個判斷是否為素數的表預處理一下。const int n 2000000 bool isprime n void doprime bool solve int64 l,int64 r,int64 a,int64 b,int64 c,int6...

素數篩選 總結

第一種 直接暴力,在這就不說了 第二種 埃氏篩法 能處理1e6以下的資料 首先,將2到n範圍內的所有整數寫下來。其中最小的素數為2,將表中所有2的倍數都劃去。表中剩餘的最小數字是3,不能被更小的數整除,所以也是素數,將表中所有3的倍數也劃去。依此類推,如果表中剩餘的最小數字為m時,m就是素數,再將m...