1. 程式人生 > >埃氏篩 線性篩(歐拉篩) 算法解析

埃氏篩 線性篩(歐拉篩) 算法解析

.net 數組 href 除了 break flag 同時 獲得 其中

埃氏曬

埃拉托斯特尼篩法,簡稱埃氏曬,是一種用來求自然數n以內的全部素數。

他的基本原理是,如果我們要獲得小於n的所有素數,那就把不大於根號n的所有素數的倍數剔除。

埃氏曬的原理很容易理解,一個合數,必然可以表示成,一個自然數 i 和一個素數的乘積。因此我們找到一個素數後,把他小於n的倍數全部標記為合數,這就是我們要做的。

void prime(int n) {
	bool flag[MAX];//0為素數 1為合數
	memset(flag, 0, sizeof(flag));
	for (int i = 2; i * i < n; i++) {
		//i為素數
		if (flag[i] == false
) { for (int j = i * i; j < n; j += i) { //將其倍數標記為合數 flag[j] = true; } } } }

上述代碼有幾個關鍵點要註意

1. 外層循環的終止條件是 i * i < n,因為我們是要把不大於根號n的所有素數的倍數剔除。

2. 內層循環,j 可以從 i * i 開始,因為 i * (2 ~ i –1 ),在之前的循環中,已經被篩去。

我們如果觀察被篩掉的數據,我們可以發現,一個合數,可能會被篩掉多次,例如,

30 = 2 * 15 = 3 * 10 = 5 * 6,所以30 就至少被2,3,5這三個質數分別篩過了,這個地方就會造成時間的浪費。我們能不能找到一種關系,使得每個合數,只被篩掉一次呢?

線性篩(歐拉篩)

歐拉篩是一種復雜度很低的素數篩選法,原因在於,每一個合數,只被篩選了一次。

void euler_sieve(int n) {
	//記錄當前找到素數的數量
	int sum = 0;

	//flag用來記錄第i個數字是否為合數  true為合數
	bool flag[MAX];
	memset(flag, 0, sizeof(flag));

	//primes用來記錄每一個找到的素數
	int primes[MAX];
	memset(primes, 0, sizeof(primes));

	for (int i = 2; i <= n; i++) {
		if
(!flag[i]) primes[sum++] = i; for (int j = 0; i * primes[j] <= n; j++) { flag[i * primes[j]] = true; if (i % primes[j] == 0) break; } } }

我們要用到的重要的定理:

\[n=Factory_{max} \ast P\]

上式中,n是一個合數,每一個合數都可以唯一的表示成如上的形式。其中

Factory是除了n以外的n的最大因數,而P滿足一下兩點:

1. P是一個素數

2. P小於等於Factory的所有因數

綜上可知,P就是n的最小質因數。

證明如下:

1.假設P為合數,則P = P1 * P2 * ···· * Pn,其中,P1<P2<····<Pn,且Pi都為質數
因此存在一個F = Fatory * P1為n的因數,且F > Fatory,
所以和Factory是n的最大的因數矛盾,故假設不成立
2.假設P大於Factory的某個因數,不妨設P>P1
因為 Factory = P1 * P2 * ···· * Pn
因此 P * P2 * ··· * Pn 必然大於Factory
所以和Factory是n的最大因數矛盾,故假設不成立

上面的定理就是歐拉篩的原理,我們創建一個數組prime[]來存儲目前找到的素數,一個數組flag[]用來標記數字是否為合數(合數為1)。我們每次枚舉一個數字i(從2開始枚舉),如果這個flag[i] == 0,則i為質數,存入prime。然後把由i和目前已找到的素數相乘得到的合數,標記為1(flag[ i * prime[n]] = 1)。

如何保證prime[n]是i * prime[n] 的最小質因數?

由於任一個數字,都可以表示成有限質數的和,所以當 i % prime[n] == 0,時,可以得出,prime[n]是 i 的一個質因數,同時也是i * prime[n]的質因數,而prime[]數組中的素數,是我們從小到大得出的,此時prime[n]是 i * prime[n]的最小質因數(這部分不容易理解),因此,prime[n+1] 等等都必定不是i * prime[n + 1]的最小質因數。

簡單舉個例子:

i = 77 = 7 * 11,此時prime[]中已經儲存了 3 5 7 9 …等素數

1. prime[1] = 3 ,3滿足 i * 3的最小質因數的條件

2.prime[2] = 5,5滿足i * 5的最小質因數條件

3.prime[3] = 7,7滿足 i * 7的最小質因數條件,但此時 i % 7 == 0,因為 i 的一個質因數也是7

4.prime[4] = 11,此時就不滿足 是最小質因數的條件了,i 中有比11更小的因數,因此 i * 11 中也有比11更小的因數。

歐拉篩解釋思路借鑒 鏈接

埃氏篩 線性篩(歐拉篩) 算法解析