求乙個範圍內的素數

2021-09-01 21:33:12 字數 2807 閱讀 6734

學演算法時候,求素數總是一道逃不掉的練習題。

好久沒寫演算法相關的練習了,學習了python 就拿它來練一下手吧。

在求素數之前,首先我們了解一下 什麼是素數。

按維基百科的說法是:

素數指在大於1的自然數中,除了1和此整數自身外,無法被其他自然數整除的數(也可定義為只有1和本身兩個因數的數)

因此我們可以總結為以下幾點:

1. 素數是自然數,且大於1

2. 素數只能被1和其本身整除

3. 最小的素數是2

4. 這也是由2延伸,素數一定時奇數,因為合數能比2整除

那麼也就是說素數實際上是奇數的乙個真子集,既然這樣我們不妨從奇數裡面把素數挑出來。

例如乙個連續的奇數集合,我們需要把裡面的素數找出來:

[3,5,7,9,11,13,15,17,19,21]

首先,判斷乙個數x是素數的方法是,分別用2 . . sqrt(x)去試除x,看能否被整除,一旦出現被整除的情況,那麼說明x不是素數。若全部試除過都沒被整除,說明x是素數。

eg:def isprime(x):

for i in range(2,math.sqrt(x)):

if x % i == 0:

return 1

return 0

事實上在用2 . . sqrt(x) 重複去試除x 是乙個不合理的過程,在上面我們分析過,素數其實是奇數的乙個真子集,那麼肯定不能被2整除,那麼用2、4、6、8等偶數去試除x其實是在做無用功,因此我們在試除時候其實是可以忽略除數是偶數的情況。我們可以作以下調整:

eg:def isprime(x):

if x % 2 == 0:

return 1

for i in range(3,math.sqrt(x),2):

if x % i == 0:

return 1

return 0

這樣就省去了除數是偶數的情況。

另外,我們看一下合數的組成。

4=2*2,6=3*2,8=2*2*2,9=3*3,15 = 3*5

每個合數總是能分解為幾個質因子,因此,我們拿合數作為除數去試除x時候也是不太合理的,也做了不少無用功,我們可以考慮優化。

首先合數可以分解為幾個質因子(y= a*b*c 其中a、b、c都是素數),那麼判斷x是否能被y整除時候,實際上是判斷x是否能分別被a,b,c整除,值得注意(y = a*b*c 即有a綜上所述,我們判斷x是否是素數時候,我們只需用2 . . sqrt(x)之間的素數去試除x 即可。

但是問題來了,如何求2 . . sqrt(x)之間的素數。

例如給定乙個x = 23 判斷它是否是素數。

方法一:

用 2 和 2 . . sqrt(23)之間的奇數去試除,嘗試次數是 2 次

方法二:

用 2 . . sqrt(x)之間的素數去試除,首先得求出2 . . sqrt(2) 之間的素數2、3 次數為2、再用求出的素數去試除x、次數再加2 所以總次數是4, 很明顯這樣的效率更低了。

我們怎樣提高方法二的效率呢?

呵呵。。。給我一張小於x 的素數表,我就可以直接省去了之前求2 . . sqrt(x) 之間的素數這個步驟了,是不!! 那麼這樣會不會快很多呢?

給定x = 107

用方法一我們所用試除次數是5次 分別要試除(2、3、5、7、9)

用方法二(假定我們是已經知道2 . . sqrt(x)之間素數的情況)所要試除的次數是4 ,分別要試除(2、3、5、7)

或許這樣還不明顯 再來,

給定x = 1999

用方法一所要試除次數是22次,分別要試除(2、3、5、7、9、、、23)

用方法二(假定我們是已經知道2 . . sqrt(x)之間素數的情況)所用次數是15次。

由此看出,隨著x的不斷增大,方法二的優勢不斷地擴大。

但問題是我們怎麼保證我們每次判斷x是否是素數時候,確保已經知道2 . . sqrt(x) 之間的素數。

最簡單的方法是維護一張素數表,那麼怎樣快速得到一張素數表呢?

1. 給定乙個自然數序列2..n

2. 首先把能被2整除的所有數去掉,當然2除外

3. 類似的,把能被3整除的數去掉,同樣3除外

4. 依次類推,一直到sqrt(n)

5. 篩選剩下的就是素數

快速得到素數表實現如下:

def prime():

num = 1000

data = [2*i+1 for i in range(num)]

data[0]=2

for i in range(4,len(data)):

j = 1

while data[j] <= math.sqrt(data[i]):

if data[j] != 0 and data[i]%data[j]==0:

data[i] = 0

continue

j += 1

data = [x for x in data if x!=0]

print data

這樣就得到了2 . . 2*num+1 之間的素數,其實這也是利用了我們上面提到的方法二求素數,判斷乙個數是否是素數,則用2 .. sqrt(x)之間的素數去試除,這樣效率是比單個單個去求省去不少時間。你說呢是不是?。。。。

好吧。。。廢話扯了一大堆。。。。

只為了說明乙個事實,

當你要判斷乙個數是否是 素數時,可以用2 和 2 . . sqrt(x)之間的奇數去試除,這樣效率比較高

當你要連續判斷若干(我指的若干是比較大的數量級)個數是否是素數時,你不妨先維護自己的一張素數表,在已知素數表的情況下幫你判斷若干個數是否是素數時,效率可以大大提高。

以上純屬扯淡,各位看官,笑笑就好,不必當真。

C ,利用陣列求乙個範圍內的質數

質數 prime number 又稱素數,有無限個。除了1和它本身以外不再有其他的因數 否則稱為合數。根據算術基本定理,每乙個比1大的整數,要麼本身是乙個質數,要麼可以寫成一系列質數的乘積 而且如果不考慮這些質數在乘積中的順序,那麼寫出來的形式是唯一的。最小的質數是2。int n 100 bool ...

大範圍內素數的求法

素數的定義 只能被1和它自己整除的自然數稱為素數,特別規定1不屬於素數。根據素數的定義,很明顯,如果乙個數是素數 它的因子只包含1和它本身。因此可以根據判別某個數的因子的方法來判斷其是否是素數。view source print?01intisprime intn 02 10 11return1 1...

求初等尤拉公式 39 40 範圍內的素數

問題描述 尤拉公式 a n n 2 n 41,求n在 39 40範圍內的素數。演算法分析 窮舉法,窮舉出 39 40範圍內的a n 再判斷a n 是否為素數 如下 view code 1 include 2 include 34 int main void 5 19 20 2122 if flag ...