素數定義:質數定義為在大於1的自然數中,除了1和它本身以外不再有其他因數。
方法一(暴力法):素數問題變化莫測,但萬變不離其宗。素數問題最核心的就是如何判斷一個數是否是素數。對於判斷一個數m是否是素數,最原始的方法就是按照素數的定義,試除2開始到m-1的整數,如果無一例外地都不能整除,則該數一定是素數。實現程序如下:
//============================ //判斷是否是素數1 //============================ #include <iostream> using namespace std; int main() { cout << "please inpout a number."; int m; cin >> m; for (int i = 2; i < m; ++i) if (m%i == 0) { cout << m << " isn't a prime\n"; return 1; } cout << m << " is a prime\n"; return 0; }
方法二(暴力法改進):我們知道如果一個數有因子的話,那么在它的平方根數以內就應該有,否則就沒有因子。例如66的平方根在8與9之間,因為66不是素數,,則它一定有比8還小的因子,我們知道66的因子是2、3、6等。
//============================ //判斷是否是素數法2 //============================ #include <iostream> using namespace std; int main() { cout << "please inpout a number."; int m; cin >> m; double sqrtm = sqrt(m*1.0); for (int i = 2; i <= sqrtm; ++i) if (m%i == 0) { cout << m << " isn't a prime\n"; return 1; } cout << m << " is a prime\n"; return 0; }
方法三(暴力法進一步改進):現在舉個例子,判斷102是否是素數,本來要從2試除到10。但事實上,中間的4、6、8、10也都無須試,只需要試除2、3、5、7。直接來說,就是只需要試除2到√m之間的所有素數即可。而所有素數(除了2和3)都滿足6*i-1或6*i+1(i=1、2、3...)。那么代碼又可以改進,如下:
//============================ //判斷是否是素數法3 //============================ #include <iostream> using namespace std; int main() { cout << "please inpout a number."; int m; cin >> m; //兩個較小數另外處理 if (m == 2 || m == 3) return 1; double sqrtm = sqrt(m*1.0); for (int i = 5; i <= sqrtm; i += 6) if (m %i == 0 || m % (i + 2) == 0) cout << m << " isn't a prime\n"; cout << m << " is a prime\n"; return 0; }
下面這種方法也是本人借鑒別人的,如有侵權請聯系我刪除。
//============================ //判斷是否是素數法4 //============================ #include <iostream> using namespace std; int main() { cout << "please inpout a number."; int m; cin >> m; //兩個較小數另外處理 if (m == 2 || m == 3) return 1; //不在6的倍數兩側的一定不是質數 if (m % 6 != 1 && m % 6 != 5) { cout << m << " isn't a prime\n"; return 0; } double sqrtm = sqrt(m*1.0); //在6的倍數兩側的也可能不是質數 for (int i = 5; i <= sqrtm; i += 6) if (m %i == 0 || m % (i + 2) == 0) cout << m << " isn't a prime\n"; //排除所有,剩余的是質數 cout << m << " is a prime\n"; return 0; }
現在對這四種方法的效率進行測試,測試代碼如下:
#include <iostream> #include <ctime> using namespace std; int isPrime_1(int num); int isPrime_2(int num); int isPrime_3(int num); int isPrime_4(int num); int main() { int num = 30000; int tstart, tstop; //分別記錄起始和結束時間 //測試第一個判斷質數函數 tstart = clock(); for (int i = 1; i <= num; i++) isPrime_1(i); tstop = clock(); cout << "isPrime_1方法的時間(ms):" << tstop - tstart << endl; //測試第二個判斷質數函數 tstart = clock(); for (int i = 1; i <= num; i++) isPrime_2(i); tstop = clock(); cout << "isPrime_2方法的時間(ms):" << tstop - tstart << endl; //測試第三個判斷質數函數 tstart = clock(); for (int i = 1; i <= num; i++) isPrime_3(i); tstop = clock(); cout << "isPrime_3方法的時間(ms):" << tstop - tstart << endl; //測試第四個判斷質數函數 tstart = clock(); for (int i = 1; i <= num; i++) isPrime_4(i); tstop = clock(); cout << "isPrime_4方法的時間(ms):" << tstop - tstart << endl; cout << endl; return 0; } int isPrime_1(int num) { for (int i = 2; i <= num - 1; i++) if (num %i == 0) return 0; return 1; } int isPrime_2(int num) { double sqrtnum = sqrt(num*1.0); for (int i = 2; i <= sqrtnum; i++) if (num %i == 0) return 0; return 1; } int isPrime_3(int num) { //兩個較小數另外處理 if (num == 2 || num == 3) return 1; double sqrtnum = sqrt(num*1.0); for (int i = 5; i <= sqrtnum; i += 6) if (num %i == 0 || num % (i + 2) == 0) return 0; return 1; } int isPrime_4(int num) { //兩個較小數另外處理 if (num == 2 || num == 3) return 1; //不在6的倍數兩側的一定不是質數 if (num % 6 != 1 && num % 6 != 5) return 0; double sqrtnum = sqrt(num*1.0); //在6的倍數兩側的也可能不是質數 for (int i = 5; i <= sqrtnum; i += 6) if (num %i == 0 || num % (i + 2) == 0) return 0; //排除所有,剩余的是質數 return 1; }
判斷1-30000之間素數的耗時:



對此,我們可以聲明一個長度為最大限制數的布爾數組。用布爾值來區別篩選出的數和質數。運用厄拉多塞篩法得代碼如下:
int countPrimes(int n) { int count = 0; //初始默認所有數為質數 vector<bool> signs(n, true); for (int i = 2; i < n; i++) { if (signs[i]) { count++; for (int j = i + i; j < n; j += i) { //排除不是質數的數 signs[j] = false; } } } return count; } 鏈接:https://leetcode-cn.com/problems/count-primes/solution/ji-shu-zhi-shu-bao-li-fa-ji-you-hua-shai-fa-ji-you/ 來源:力扣(LeetCode)
bitset<4> bitset1; //無參構造,長度為4,默認每一位為0 bitset<8> bitset2(12); //長度為8,二進制保存,前面用0補充 string s = "100101"; bitset<10> bitset3(s); //長度為10,前面用0補充 char s2[] = "10101"; bitset<13> bitset4(s2); //長度為13,前面用0補充 cout << bitset1 << endl; //0000 cout << bitset2 << endl; //00001100 cout << bitset3 << endl; //0000100101 cout << bitset4 << endl; //0000000010101
可用函數
bitset<8> foo ("10011011"); cout << foo.count() << endl; //5 (count函數用來求bitset中1的位數,foo中共有5個1 cout << foo.size() << endl; //8 (size函數用來求bitset的大小,一共有8位 cout << foo.test(0) << endl; //true (test函數用來查下標處的元素是0還是1,並返回false或true,此處foo[0]為1,返回true cout << foo.test(2) << endl; //false (同理,foo[2]為0,返回false cout << foo.any() << endl; //true (any函數檢查bitset中是否有1 cout << foo.none() << endl; //false (none函數檢查bitset中是否沒有1 cout << foo.all() << endl; //false (all函數檢查bitset中是全部為1
現在言歸正傳來講如何判斷素數,加入要我們判斷2到1億之間有多少素數,首先我們可以調用上面的方法1億次,到當你這樣干的時候,估計你電腦要運行幾十分鍾才能有結果。現在我們就采用空間換時間的方法。設置一個空間為1億的bitset來標記哪些是素數,因為我們知道如果一個數不是素數,那么它的倍數也肯定不是素數。借助這個思想,我們有如下程序:
//===================================== //利用bitset判斷2到1億之間的素數個數 //===================================== #include<iostream> #include<bitset> using namespace std; int main() { bitset<100000000> *p=new bitset<100000000>; p->set(); //每個元素置1 for (int i = 2; i <= 10000; ++i) if (p->test(i)) //第i位為0返回false,為1返回true; for (int j = i*i; j < p->size(); j += i) p->reset(j); //每個元素置0 int num = 0; for (int i = 2; i < 100000000; ++i) if (p->test(i)) num++; cout << num << endl; delete[] p; return 0; }