1. 程式人生 > 實用技巧 >3.篩質數 質數

3.篩質數 質數

篩質數的核心思想:

先把所有數放進一個數組

然後從前往後看,把每一個數的倍數刪掉

第一個數是2,就把所有2的倍數刪掉,4,6,8,10,12

第二個數是3,就把所有3的倍數刪掉,6,9,12

第二個數是4,就把所有4的倍數刪掉,8,12

第二個數是5,就把所有5的倍數刪掉,10

以此類推

這樣篩完之後,所有剩下的數就是質數

證明:對於任何一個數p而言,如果p沒有被刪掉的話,就意味著從2到p - 1中的任何一個數,都沒有把p刪掉

說明p不是2到p - 1中間任何一個數的倍數,也即2到p - 1中間不存在p的約數,所以p是一個質數

質數定理:1 ~n中,有n / ln (n)個質數

線性篩:

 1
#include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1000010; 4 int primes[N], cnt; 5 bool st[N]; 6 void get_primes_1(int n) { 7 //樸素篩法,時間複雜度近似O(n log n) 8 for (int i = 2; i <= n; i++) { //從2到n列舉 9 if (!st[i]) { //如果這個數沒有被篩過的話,說明是一個質數 10 primes[cnt++] = i;
11 } 12 //再把每一個數的倍數刪掉 13 for (int j = i + i; j <= n; j += i) { //最樸素方法 14 st[j] = true; 15 } 16 } 17 } 18 void get_primes_2(int n) { 19 //埃氏篩法,時間複雜度O(n log log n),近似O(n) 20 for (int i = 2; i <= n; i++) { //從2到n列舉 21 if (!st[i]) { //如果這個數沒有被篩過的話,說明是一個質數
22 primes[cnt++] = i; 23 for (int j = i + i; j <= n; j += i) { //最樸素方法 24 st[j] = true; 25 } 26 } 27 //並不需要把每一個數的倍數刪掉,只把所有質數的倍數刪掉就可以了 28 //可以把迴圈放進判斷裡面去 29 } 30 } 31 void get_primes_3(int n) { 32 //線性篩法的基本思路也是一樣的:爭取把每個合數,用它的某一個質因子篩掉 33 /* 34 線性篩法的核心思路:每一個合數,只會被它的最小質因子篩掉 35 */ 36 //線性篩法,時間複雜度O(n) 37 for (int i = 2; i <= n; i++) { //從2到n列舉 38 if (!st[i]) { //如果是一個質數的話 39 primes[cnt++] = i; //加進去 40 } 41 //從小到大列舉所有質數 42 for (int j = 0; primes[j] <= n / i; j++) { 43 st[primes[j] * i] = true; 44 if (i % primes[j] == 0) { //當這句話成立時,就意味著primes[j]一定是i的最小質因子 45 break; 46 } 47 } 48 } 49 } 50 /* 51 當n = 1e6時,埃氏篩法和線性篩法執行時間差不多 52 當n = 1e7時,線性篩法比埃氏篩法快一倍 53 */ 54 int main() { 55 int n; 56 cin >> n; 57 get_primes_3(n); 58 cout << cnt << endl; 59 return 0; 60 }