素数筛选实现
一般的素數篩選的思路是從2開始,將所有2的倍數去掉,然后從3開始,將3的倍數去掉,然后從下一個素數x開始,將x的倍數去掉...,這樣可以將所有素數的倍數去掉。實現代碼如下:
1 int PrimeOld() 2 { 3 int i; 4 5 cnt = 0; 6 memset(prime, true, sizeof(prime)); 7 for (i = 2; i < MAX; i++) 8 { 9 if (prime[i]) 10 { 11 primeUse[cnt++] = i; 12 for (int j = i + i; j < MAX; j += i) 13 { 14 prime[j] = false; 15 allCount++; 16 } 17 } 18 } 19 }從上面的代碼不難看出,還是會存在重復訪問的情況,如i?=?2和?i?=?5的情況都會訪問prime[20]。因此改進這個算法的方法就是盡量重復訪問的次數,盡量讓prime[j]只能被訪問一次。上面代碼的思路是素數的倍數一定不是素數,那么任何一個數與素數的乘積肯定也不是素數,基于這個思想的代碼如下:
1 int PrimeNew() 2 { 3 int i; 4 5 memset(prime, true, sizeof(prime)); 6 allCount = 0; 7 cnt = 0; 8 for (i = 2; i < MAX; i++) 9 { 10 if (prime[i]) 11 primeUse[cnt++] = i; 12 for (int j = 0; j < cnt && i * primeUse[j] < MAX; j++) 13 { 14 prime[i * primeUse[j]] = false; 15 allCount++; 16 if (i % primeUse[j] == 0) 17 break; 18 } 19 } 20 }上面代碼和前面最大代碼的不同是產生剔除整數的方法不同,前者是根據當前處理到的素數的倍數來剔除,后者則是根據當前整數與已經產生的素數的乘積來剔除,效果是一樣的。但后者有一個關鍵的優化就是當當前處理的整數已經是某個素數的倍數時,退出剔除。如果沒有這個優化,那么還是有些prime[j]被重復訪問了,如prime[12],它顯示通過prime[6?*?2]被訪問,然后通過prime[4?*?3]被訪問。我們應該讓12只被12的最小素因子2訪問,即計算6?*?2時訪問,而不應該在4?*?3時訪問,所有對于任何數如果它是當前素數的倍數那么它就不能再與素數表中該素數之后的素數相乘了。
測試結果也可以看出后一種方法能夠很有效的減少對同一個prime[j]的訪問。
上面的測試結果是通過對1~100000000之間的素數篩選。times表示的是篩選所用的時間,AllCount表示再第二重循環中訪問prime數組的總次數。可以很明顯的看出,改進的方法在時間上有了比較大的提升。測試的源代碼:https://github.com/cc1989/test/blob/master/primes.cpp
參考:http://blog.csdn.net/morewindows/article/details/7347459
總結
- 上一篇: JAVA构造方法,继承关系和SUPER关
- 下一篇: ubuntu 13.04下MYSQL 5