[演算法] 埃式篩和歐式篩演算法簡要介紹
阿新 • • 發佈:2021-11-21
本文對素數篩選法中的埃拉託斯特尼篩選法和尤拉篩選法進行了簡要的介紹。
一、摘要
素數篩是一種用於判斷小於n的所有素數的演算法。其中包括埃拉託斯特尼篩(埃式篩)和尤拉篩(線性篩、歐式篩)兩類,本文將簡要介紹埃式篩和歐式篩,並未對其中原理進行詳細的介紹,若讀者想了解兩種篩選法的原理請檢視演算法學習筆記(17): 素數篩。
二、埃式篩和尤拉篩介紹
1. 埃式篩
埃式篩的一個思路是,使用一個數組vector<bool> isPrime
表示數字i
是否是素數。從數字2開始遍歷所有的小於n的數字i
:
- 假如
數字i
是素數,即isPrime[i]=true
,那麼就把所有大於等於i*i
,小於n
的數字i的倍數
標記為不是素數,即令isPrime[i*j]=false
。 - 假如
數字i
程式碼如下:
#include <vector> #include <iostream> using namespace std; int main() { int n = 50; vector<bool> isPrime(n, true); isPrime[0] = isPrime[1] = false; for (int i = 2; i < n;i++) { if (isPrime[i]) { // 如果數字i為素數,那麼就把大於等於i*i的,i的倍數設為不是素數 for (int j = i * i; j < n; j += i) { isPrime[j] = false; } } } // 輸出所有小於n的素數 for (int i = 0; i < isPrime.size(); i++) { if (isPrime[i]) { cout << i << " "; } } return 0; }
2. 歐式篩
埃式篩存在一個問題是:例如,對於
合數12
,當遍歷到數字i=2
時,會把i*6=2*6=12
標記為合數,當遍歷到數字3
時,又會把3*4=12
標記為合數,因此埃式篩會存在對於一個合數多次標記的問題。歐式篩演算法消除了這個問題。
歐式篩的思想是,使用一個數組vector<bool> isPrime
表示數字i
是否是素數,另外使用另一個數組vector<int> prime
記錄下所有已經找到的素數。從數字2
開始遍歷所有數字i
:
- 假如
數字i
為素數,即isPrime[i]=true
,就把數字i
加入到陣列prime
;之後用陣列prime
中已找到的所有素數prime[j]
數字i
相乘,標記數字i*prime[j]
為合數,直到i*prime[j]
大於等於n。 - 假如
數字i
為合數,即isPrime[i]=false
,就直接用陣列prime
中已找到的所有素數prime[j]
與數字i
相乘,標記i*prime[j]
為合數,直到i*prime[j]
大於等於n或者i%prime[j]==0
。
程式碼如下:
#include <vector>
#include <iostream>
using namespace std;
int main() {
int n = 50;
vector<bool> isPrime(n, true);
vector<int> prime;
isPrime[0] = isPrime[1] = false;
for (int i = 2; i < n; i++) {
if (isPrime[i] == true) {
prime.push_back(i);
}
for (int j = 0; j < prime.size() && i * prime[j] < n; j++) {
isPrime[i * prime[j]] = false;
if (i % prime[j] == 0) {
break;
}
}
}
for (int i = 0; i < prime.size(); i++) {
cout << prime[i] << " ";
}
return 0;
}
三、參考
[1.] 演算法學習筆記(17): 素數篩
[2.] Leetcode 計算質數 -- 埃氏篩、線性篩解析