素數篩選法


當一個數不算大的時候,可以用普通的求素數的方法去求,但是如果一個數過大的話,就像讓求1-十億之間素數的個數,普通方法就不行了,這事就需要用到素數篩選法,他的時間復雜度是O(n),盡管不算很好,但是,也算是目前為止比較快的一種方法了,它是以空間換取時間,現在的計算機,空間有的是,但是時間是非常珍貴的。效率問題特別重要。他的原理就是標記,防止重復判斷,這樣提高了效率。就像2是素數,所有是2的倍數的肯定都不是素數,這時候標記上,接着判斷3是素數,所有是3的倍數的都肯定不是素數,這時就要標記上,以此下去,執行到根下(總數),這樣就會得到一個素數表,所有沒有被標記的都是素數,下面是具體的代碼實現,代碼里面有注釋。寫的很清楚。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #define MAX 1000000000//定義一個數組長度
 5 bool prime[MAX + 1];//素數表
 6 int main()
 7 {
 8     int i, j, count = 0;//count為計數器
 9     memset(prime, true, sizeof(prime));//初始化,將prime數組全部都初始化為true
10     prime[0] = prime[1] = false; prime[2] = true;//0,1都不是素數,所以為false,2是素數,所以為true
11     for(i = 2; i * i <= MAX; i ++)/*從2開始進行遍歷, i * i <= MAX 就等價於 i < sqrt(MAX);但是前者更不容易出錯
12      具體為什么是sqrt就不用說了吧,普通的方法中也有這個*/   
13     {
14         if(prime[i])//如果沒有被標記的話將它的倍數的數標記(標記就是將它賦值為false)
15         {
16             for(j = i + i; j <= MAX; j += i)//因為是從2開始的,所以j = i * i 就行了,最小的一個他的倍數的就是i * i了,不可能有比這個更小的了
17                 prime[j] = false;//標記為false
18         }
19     }
20     for(i = 2; i <= MAX; i ++)//遍歷一下,找出所有的素數來
21         if(prime[i])
22                 count ++;//如果沒有被標記,計數器++
23     printf("count is :%d\n", count);
24     return 0;
25 }

這時最基礎的,當然還可以進行改進,改進的越多,執行效率就越快,例如:因為偶數不可能為素數,它是肯定能被2整除的,所以可以舍掉所有的偶數,這樣會減少一半的時間,當然空間也會減少一半,如果十億的話,開個5億的數組就行了,for循環中的i 應該是從3開始了,然后一次加2,這樣標記會更快,具體代碼就不實現了。大致原理差不多。這時一個非常基礎的算法。素數也是用到的比較多的。當然也可以琢磨點在改進改進,目前為止我沒有想到更好的,如果有哪位大神有更好的方法,麻煩留一下言告知一下,謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM