转自:http://blog.csdn.net/left_la/article/details/8807040
1、简陋的算法:
- void prime(int n)
- {
- for (int i = 2; i < n; ++i)
- {
- int j;
- for (j = 2; j <= sqrt(i); ++j) // 如果i不能被2到sqrt(i)之间的所有整数所整除,则其为素数
- {
- if (i%j==0) break;
- }
- if (j>sqrt(i))
- cout<<i<<" ";
- }
- cout<<endl;
- }
2.一位博友的解法(http://blog.csdn.net/sgbfblog/article/details/7860064)
最基本的想法就是对1到N得每个数进行判断,如果是素数则输出。一种改进的方法是不需要对1到N所有的数都进行判断,因为偶数肯定不是素数,而奇数可能是素数,可能不是。2,3,5都是素数,这可以直接得到。然后我们可以跳过2与3的倍数,即对于6n,6n+1, 6n+2, 6n+3, 6n+4, 6n+5,
我们只需要判断6n+1与6n+5是否是素数即可。
判断某个数m是否是素数,最基本的方法就是对2到m-1之间的数整除m,如果有一个数能够整除m,则m就不是素数。判断m是否是素数还可以进一步改进,不需要对2到m-1之间的数全部整除m,只需要对
2到根号m之间的素数整除m就可以。如用2,3,4,5...根号m整除m。其实这还是有浪费,因为如果2不能整除,则2的倍数也不能整除,同理3不能整除则3的倍数也不能整除,因此可以只用
2到根号m之间小于根号m的素数去除即可。(
据我(lsj)了解,任何一个大于2的自然数都可以写成几个质数相乘的形式,不知道对不对)
给出一个最基本的解法就是预先可得2,3,5为素数,然后跳过2与3的倍数,从7开始,然后判断11,然后判断13,再是17...规律就是从5加2,然后加4,然后加2,然后再加4。如此反复即可,如下图所示,只需要判断7,11,13,17,19,23,25,29...这些数字。对这些数进行判断,如果是素数则输出。
判断是否是素数采用改进后的方案,即对2到根号m之间的数整除m来进行判断。需要注意一点,不能直接用根号m判断,因为对于某些数字,比如121,开根号后得到的不一定是11,可能是10.999999,所以最好使用乘法判断,如代码中所示:
后来,我想了想,为什么这位博友能这么做。我们知道这样一个结论,素数只可能是6n-1或者6n+1,(这位博友证明了一下http://blog.csdn.net/code_pang/article/details/7880245)。我们选择5开始判断(因为5 = 6*1-1),根据上面这个结论,我们只需需要判断6n-1和6n+1,
而
5 = 6*1 - 1,那么接下来我们就应该判断6*1 + 1 =7 ,再下来是 6 * 2 - 1 = 11 = 7 + 4 = 5 +6。。。。。意会一下就明白了。按照这位博友的意思就是先加2,再加4。这位博友这种思想是对的,小小的思考了下。
- #include <stdio.h>
- #define MAXSIZE 100
- #define YES 1
- #define NO 0
- int main(void)
- {
- int prime[MAXSIZE]; /* array to contains primes */
- int gap = 2; /* increasing gap = 2 and 4 */
- int count = 3; /* no. of primes */
- int may_be_prime = 5; /* working variable */
- int i, is_prime;
- prime[0] = 2; /* Note that 2, 3 and 5 are */
- prime[1] = 3; /* primes. */
- prime[2] = 5;
- while (count < MAXSIZE) { /* loop until prime[] full*/
- may_be_prime += gap; /* get next number */
- gap = 6 - gap; /* switch to next gap */
- is_prime = YES; /* suppose it were a prime*/
- for (i = 2; prime[i]*prime[i] <= may_be_prime && is_prime; i++)
- if (may_be_prime % prime[i] == 0) /* NO */
- is_prime = NO; /* exit */
- if (is_prime) /* if it IS a prime... */
- prime[count++] = may_be_prime; /* save it */
- }
- printf("\nPrime Number Generation Program");
- printf("\n===============================\n");
- printf("\nFirst %d Prime Numbers are :\n", count);
- for (i = 0; i < count; i++) {
- if (i % 10 == 0) printf("\n");
- printf("%5d", prime[i]);
- }
- return 0;
- }
3、埃拉托斯特尼筛法:
给出要筛数值的范围n,找出以内的素数。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复下去......。
- void primeFilte(int n)
- {
- bool *filter = new bool[n+1];
- for (int i=2; i<=n; i++)
- filter[i] = true;
- for (int i=2; i<=sqrt(n); i++) //注意我们这里只需要筛选到sqrt(n)
- {
- if (filter[i])
- {
- int j = i*2;
- while (j<=n)
- {
- if (filter[j])
- filter[j] = false;
- j+=i;
- }
- }
- }
- for (int i=2; i<=n; i++)
- if (filter[i]) cout<<i<<" ";
- cout<<endl;
- delete []filter;
- }
个人觉得,前面代码在给filter[i]赋值的时候就可以把偶数直接踢掉,这样我们后面直接从3开始踢就好了。
#include <iostream>
#include <cmath>
using namespace std;
void primeFilte(int n)
{
bool *filter = new bool[n+1];
for (int i=2; i<=n; i++) {
if(i & 0x1 || i==2) filter[i] = true;
else filter[i] = false;
}
for (int i=3; i<=(int)sqrt((long double)n); i++)
{
if (filter[i])
{
int j = i*2;
while (j<=n)
{
if (filter[j])
filter[j] = false;
j+=i;
}
}
}
for (int i=2; i<=n; i++)
if (filter[i]) cout<<i<<" ";
cout<<endl;
delete []filter;
}
int main()
{
primeFilte(100);
system("pause");
return 0;
}