當一個數不算大的時候,可以用普通的求素數的方法去求,但是如果一個數過大的話,就像讓求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,這樣標記會更快,具體代碼就不實現了。大致原理差不多。這時一個非常基礎的算法。素數也是用到的比較多的。當然也可以琢磨點在改進改進,目前為止我沒有想到更好的,如果有哪位大神有更好的方法,麻煩留一下言告知一下,謝謝!