C++之尋找素數(素數篩)


一、題目

題目描述:

  給你一個正整數N,在[2,N]這個區間內有多少個素數。

輸入描述:

  先輸入一個整數T,代表有T(1<=T<=100000000)組數據,然后有T行正數N(1<N<=10000000).

輸出描述

  對於每一個N,輸出在這[2,N]區間內,有多少個素數。

二、暴力素數篩

  整體實現思想:兩層循環,遍歷每一個數,判斷其是否為素數。

  代碼如下:

 1 //暴力素數篩
 2 vector<int> Find_Prime_number1(int n)  3 {  4     vector<int> ans;  5 
 6     //從2開始,1不是素數
 7     for (int i = 2; i <= n; i++)  8  {  9         //默認是素數
10         int flag = 1; 11         //判斷i是否是素數
12         for (int j = 2; j < i; j++) 13  { 14             if (i % j == 0) 15  { 16                 flag = 0; 17                 break; 18  } 19  } 20         if (flag) 21  ans.push_back(i); 22  } 23 
24     return ans; 25 }

  對其進行簡單的優化,第二層的結束條件可以優化為sqrt(i),因為右面的所有數字都在面被遍歷過。

  代碼如下:

 1 //暴力素數篩優化
 2 vector<int> Find_Prime_number2(int n)  3 {  4     vector<int> ans;  5 
 6     //從2開始,1不是素數
 7     for (int i = 2; i <= n; i++)  8  {  9         //默認是素數
10         int flag = 1; 11         //優化循環結束調節,開方
12         for (int j = 2; j <= sqrt(i); j++) 13  { 14             if (i % j == 0) 15  { 16                 flag = 0; 17                 break; 18  } 19  } 20         if (flag) 21  ans.push_back(i); 22  } 23 
24     return ans; 25 }

三、朴素素數篩(埃拉托斯特尼篩法)

  整體實現思想:遍歷到的每一個素數,將其的倍數設置為合數,避免對每一樹的判斷,可以大幅度節省時間,但是注意第二層循環的開始條件,從而i*i開始,而不是i*2。時間復雜度為O(n*loglogn)。

  代碼如下:

 1 //朴素素數篩(埃拉托斯特尼篩法),時間復雜度為O(n * loglogn)
 2 vector<int> Find_Prime_number3(int n)  3 {  4     vector<int> ans;  5 
 6     vector<bool> flag(n + 1, true);  7 
 8     //0和1不是素數,直接初始化好
 9     flag[0] = 0; 10     flag[1] = 0; 11 
12     //從2開始,1不是素數
13     for (int i = 2; i <= n; i++) 14  { 15         //如果當前數字是素數
16         if (flag[i]) 17  { 18             //i的倍數標記被不是素數
19             for (int j = i * i; j <= n; j += i) 20  { 21                 flag[j] = false; 22  } 23  ans.push_back(i); 24  } 25  } 26 
27     return ans; 28 }

四、線性素數篩(歐拉篩法)

  整體實現思想:在朴素素數篩的過程中我們會重復篩到同一個數,例如12同時被2和3篩到,30同時被2、3和5篩到。所以我們引入歐拉篩,也叫線性篩,可以在 [公式] 時間內完成對2~n的篩選。它的核心思想是:讓每一個合數被其最小質因數篩到。

  代碼如下:

 1 //線性素數篩(歐拉篩法),時間復雜度為O(n)
 2 vector<int> Find_Prime_number4(int n)  3 {  4     vector<int> ans;  5 
 6     vector<bool> flag(n + 1, true);  7 
 8     //0和1不是素數,直接初始化好
 9     flag[0] = 0; 10     flag[1] = 0; 11 
12     //從2開始,1不是素數
13     for (int i = 2; i <= n; i++) 14  { 15         //如果當前數字是素數
16         if (flag[i]) 17  ans.push_back(i); 18 
19         //顯示標記合數
20         for (int j = 1; j <= ans.size() && i * ans[j-1] <= n; j++) 21  { 22             flag[i*ans[j - 1]] = false; 23             if (i % ans[j - 1] == 0) 24                 break; 25  } 26  } 27 
28     return ans; 29 }

五、參考文章

https://blog.csdn.net/qq_42685893/article/details/86761727

https://zhuanlan.zhihu.com/p/100051075#


免責聲明!

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



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