筛选法:
首先:找出第一个素数,把他的倍数赋值为0
其次:找出其后第一个不为0的数,该数为素数,把他的倍数赋值为0
最后:重复上述步骤....
筛选法也叫厄拉多塞筛法,因为素数的倍数必然不是素数,所以把素数的倍数全置为0,用一个新的数组保存那些不为0 的数,即为素数
#include <stdio.h>
#include <malloc.h>
void PutPrimer(int n)//筛选法求素数
{
int *arr = (int*)malloc(sizeof(int)*n);//动态申请内存
int k=0; //记录素数的个数
for(int i=0;i<n;i++)//初始化数组数据,赋值为1~n
{
arr[i]=i+1;
}
//动态申请内存单独存储素数
//int *brr = (int*)malloc(sizeof(int)*n/2);//动态申请内存,n以内素数最多占50%且仅当n等于2
for(int i=1;i<n;i++) //arr[1]=2;第一个素数
{
if(arr[i]!=0) //为0则为素数的倍数,不是素数
{
//brr[k++]=arr[i]; //该数为素数,存放在brr中
arr[k++]=arr[i];
for(int j=i+1;j<n;j++) //把该数的倍数置为0
{
if(arr[j]%arr[i]==0)
{
arr[j]=0;
}
}
}
}
for(int i=0;i<k;i++) //打印所有素数
{
//printf("%d ",brr[i]);
printf("%d ",arr[i]);
}
puts(""); //等价于printf("
");
}
在上述代码中我们发现,数组brr[]其实可有可无,可以优化算法(避免申请brr数组时产生开销)。把每一个素数从原数组开头重新排列,用k记录素数的个数。
暴力枚举:
暴力枚举法核心在判断该数是否为素数,由素数的定义可知素数是在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数,因此可以用循环的思想,从2开始循环到n为止如果有一个因数则这个数就不是素数。
#include <stdio.h>
#include <math.h> //动态库 -lm
void PutPrimer(int n)//打印素数,参数为0~n
{
int j;
for(int i=3;i<n;i++)
{
//for(j=2;j<i;j++)//2,3,4,5,6,7
for(j=2;j<=sqrt(i*1.0);j++) //O(n^1/2)
{
if(i%j == 0)//能够整除,说明不是素数
{
break;
}
}
//if(j >= i)
if(j > sqrt(i*1.0))
{
printf("%d
",i);
}
}
}
int main()
{
PutPrimer(100);
return 0;
}
同样的,在判断2~n的过程也是可以优化的。举个例子:2*2=4,1*4=4 我们可以发现每一个数分解因式后必然一个因数大于根号n,一个因数小于根号n,极端情况下类似2×2=4的情况,两个因数都等于根号n,因此可以把判断条件换成2~根号n。