问题描述:
输入一个整数n(<=100),求1~n之间的所有质数并且输出,并且按每行5个输出
问题分析:
求一个范围内的质数个数,按传统方法是外层做一个循环(循环控制变量为i),取出这个范围的每一个数i;内层再做一个循环(循环控制变量为j),依次判断这个数i%[2,i-1]否为为0,若i在[2,i-1]这个区间有一个数除的尽,则i这个数不是质数。对于1~n(用户输入)每个数都会做一次内层循环判断,且当n越大时,内外层循环嵌套的运算数量也越大,效率低下。
基于这种情况,出现了筛选法的应用,可以避免重复的,不必要的循环,循环次数大大降低。直接看代码:
#include <stdio.h>
#include <string.h>
#define N 100
int main(void)
{
int prime[N+1];//prime[i]的值为0表示i在筛子上,值为1表示不在筛子上
int n;//输入30,求1~n之间的质数(可随意)
scanf("%d",&n);
memset(prime,0,sizeof(prime));//将prime中所有的元素值清0
prime[1]=1;//默认1不是质数
for(int i=2;i*i<=n;i++)
{
if(prime[i]==0)
{
for(int j=2*i;j<=n;j+=i)//筛去i的2倍(i*2,该语句仅执行一次),3倍(j+=i),4倍(j+=i)…,这些数肯定不是质数(因为i除了被1和自身整除外,还能被它自身倍数整除)。
{
prime[j]=1;
}
}
}
int t = 0 ; //统计质数个数,以控制每行输出5个
for(int i = 1; i <= n; i++)
{
if(prime[i] == 0) //i是质数,则输出,计数,一行输出5个
{
printf("%-2d ", i);
t++;
if(t%5 == 0) printf("\n"); //一行已输出5个
}
}
return 0;
}
输出:
以上代码求2~30之间的质数的模拟过程:
-
当i=2:prime[2]=0(即2是质数,数组下标即对应我们要操作的数),prime[4],prime[6],prime[8]…prime[30]置成1。(即在2~30范围内,2对应的倍数的数都不是质数)
-
当i=3:由于prime[3]=0,把prime[6],prime[9],…prime[27],prime[30]置成1
-
当i=4:由于prime[4]=1,不继续筛选步骤。因为4不是质数,因为4已经作为因子2的倍数被筛选掉
-
当i=5:由于prime[5]=0,把prime[10],prime[15],prime[20],prime[25],prime[30]置成1。
-
当i=6:6>sqrt(30)算法结束(即6*6>30)。