學演算法時候,求素數總是一道逃不掉的練習題。
好久沒寫演算法相關的練習了,學習了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 ...