求N內的所有素數

2021-07-13 01:57:03 字數 3405 閱讀 2787

1、素數及相關

素數,又稱質數,在乙個大於1的自然數中,除了1和此整數自身之外,不能被其他自然數整除的數。

比1大但不是素數的數稱為合數。

1和0既不是素數,也不是合數。

算術基本定理證明每個大於1的正整數都可以寫成素數的乘積,並且這種乘積的形式是唯一的。

2、試除法求素數

演算法描述:根據素數的定義可知,不能被1和自身外的整數整除的數為素數。所以,我們可以得知,判斷乙個素數是否為素數只要看它是否能被2~sqrt(i)間的數整數即可。而求n內所有素數則是迴圈重複上述過程。

c語言實現如下所示。

#include #include #include #include //試除法

#define num 10000

int test_prime(int n)

}if(j > sqrt(i))

}free(num);

return count;

}int main()

測試結果如下所示(測試在vc6.0下進行)。

從上面可以看出,當資料很大時,時間消耗增長的比較快。

3、試除法的優化方案

仔細研究試除法,可以發現以下幾個問題:

1> 在迴圈條件中重複呼叫了sqrt(i),這顯然是比較浪費時間的;

2> 判斷素數,真的需要拿2-sqrt(i)間的所有整數去除嗎?我們知道,合數都可以分解成若干質數,所以,只要2-sqrt(i)間的質數不能整除i即可;

c語言實現如下所示。

//求n內的所有素數

#include #include #include #include //試除法

#define num 1000000

int test_prime(int n)

for(j = 0; j < stop; j++)

}if(j == stop)

}free(num);

return count;

}int main()

測試結果如下所示。

相對於優化前的演算法,時間提供了很多。特別是在時間增長曲線的幅度變小了,n值越大,優化後的演算法比優化後的演算法效率更高。

4、合數過濾篩選法

演算法描述:由質數的定義可以知道,質數n不能被2-(n-1)間的任何整數整除;反過來看,只要能被2-(n-1)間的任何整數整除的n,都不是素數。所以,我們採用排除法:就是對n以內的所有數,只要逐個 去除 值為2-(n-1)的倍數的數,剩下的就是素數。

c語言實現如下所示。

//合併篩選法

#include #include #include #include //試除法

#define num 10000

int test_prime(int n)

//以2-(n-1)為因子過濾合數

for(i = 2; i <= n-1; i++)

}//統計素數個數

for( i = 2; i<= n; i++)

}free(num);

return count;

}int main()

測試結果如下所示。

上述程式好多地方採用了比較低效的做法,為了與後文的優化作比較,這也是像我一樣的初學者通常採用的版本,因此,要學會優化。

5、合併篩選法優化方案

上述演算法存在的問題是:

1> 在外層迴圈,需要一直執行到n-1嘛?不要,因為n/2-(n-1)之間的數顯然不能整除出n;

2> 在內層迴圈中重複使用i*j顯然是低效的,考慮到計算機中加減運算速度比乘除快,可以考慮變乘法為加法;

3> 在迴圈修改flag的過程中,其實有很多數被重複計算若干次,比如6 = 2*3 = 3*2,被重複置零,所以,可以進行避免;

c語言實現如下所示。

//合併篩選法的優化方案

#include #include #include #include #define num 300000

int test_prime(int n)

//從i的2倍開始過濾

for(j = i + i; j <= n;j+=i)

else}}

第一部分紅色,我將原來的奇數和偶數進行判斷,變為了只對奇數進行判斷;

第二部分紅色,我將奇數的倍數為偶數的直接剔除,變成只對倍數為奇數的進行賦值;

以上兩者改變,都基於開始時,已經將偶數剔除。

對num = 300000測試如下所示。

時間僅為7毫秒,比 優化前num = 300000時,時間更快。

//合併篩選法的優化方案

#include #include #include #include #include #define num 10000

int test_prime(int n)

num[2] = 1;

num[3] = 1;

num[5] = 1;

num[7] = 1;

num[11] = 1;

num[13] = 1;

// 從17開始過濾,因為2,3,5,7,11,13的倍數早被去掉了

// 到n/13止的

int stop = n/13;

for (i=17; i <= stop; i++)

// 從i的17倍開始過濾

int step = i*2;

for (j=i*17; j <= n; j+=step)

}// 統計素數個數

for (i=2; i<=n; i++)

}// 釋放記憶體

free(num);

return count;

}int main()

測試結果如下所示。

說實話,這種思想真的很讚,現在的我是無法想到的,感謝作者,讓我有了更廣泛的見識。

7、其他

除了以上幾種演算法外,如拉賓公尺勒素數測試演算法,感覺這個演算法比較難,先好好看看,等弄懂了,然後補上。

通過今天的糾結,對於求素數有了更加深刻的了解和認識,感覺自己還差很多,需要更加的努力。

doforfun_net,給我了很大的啟發,學到了很多。

求N以內的所有素數

如下 include stdafx.h include conio.h include math.h include malloc.h typedef long long prime typedef struct pn 構造素數節點 struct pn next pn static pn prime...

篩法求2到n的所有素數

我用了三種方法 先上 public static int isprime int n for int i 2 i n i int prime newint n int pnum 0 for int i 2 i n i return prime public static int eratosthen...

計算n以內的所有素數

尋找素數我們最常用的方法是暴力求解法,就是沒對於每個數n,從2找到n的開方,判斷每個數是不是素數,時間複雜度度為o nlog2n 時間複雜度高,是肯定的,因為太 暴力 所以,我想換個思路,其實求素數的過程,就是去除合數的過程,如果對於乙個雜湊,去除了合數,那麼留下的就是素數了,時間複雜度接近o n ...