素数的定义
质数又称素数。 一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数。
方法一:试除法🐾
原理
用2到(本身-1)的数除以本身,但凡有一个能整除的,这个数都不是素数。【素数不能被除了1和它本身外的其他自然数整除。】
#include<stdio.h>
int main()
{
int i = 100, j = 0;
for (i; i < 200; i++)
{
for (j = 2; j < i; j++)
{
if (i % j == 0)
{
break;
}
}
if (i == j)
{
printf("%d ", i);
}
}
return 0;
}
思路讲解
要使用两层for循环,外层用来实现100到200的遍历。内层用来判断每个数是不是素数。
从 j=2 到 j<本身,即用2到(本身-1)的数依次除以本身。用if来判断每个数能否整除,如果能整除,就不用再判断了,使用break跳出内层for循环。
注意:一个break只能跳出一层循环。所以break后仍在外层循环中操作, i++,100到200的数继续遍历。
因为进入内层for循环的条件是j<i,所以当 j++到等于i时,无法再进入循环,但是 j 已经被++的这个事实无法撤回。
j 能够被++到与 i 相等,说明在此之前都没有出现“整除(i % j == 0)”的情况,因为整除会遇到break,这时 j 的++就会被打断,也就是 j 活不到相等那会就夭折了。因此(i == j)时的就是素数,打印即可。
方法二:假设法🐾
#include<stdio.h>
int main()
{
int i = 100, j, count = 0;
for (i = 100; i <= 200; i++)
{
int flag = 1;
for (j = 2; j < i; j++)
{
if (i % j == 0)
{
flag = 0;
break;
}
}
if (flag == 1)
{
count++;
printf("%d ", i);
}
}
printf("\n%d", count);
}
原理
(你知道“攻1”和“受0”吗?无意冒犯)
假设全部都是素数并全部标记为1。
(将军,登记的时候都是“攻”。)
全部带去检验,如果发现不是素数 (娇),就把标记变为0。
(这个这么娇,是“受”吧)
只输出标记为1的。
(走,只有“攻”才能上战场!)
注意:因为标记flag不是绑在数上的,所以它是被每个数“暂时拥有”,辨明身份,立马使用,决定是否输出。所以它应该放在循环内。
思路讲解
遍历100到200的数。
建立标记变量flag=1。
用试除法判断是否为素数。
如果不是素数,就把标记flag变为0,并break退出内层循环。在外层循环中继续向下执行if,因为flag=0,所以无法进入if。
如果是素数,就不会被除了1和它本身外的其他自然数整除,即无法进入内层循环的if,即flag=1不会被改变。当结束内层循环继续向下执行时,这个数可以进入外层循环的if,被打印。
回到外层循环开头,i++,符合外层循环条件i<=200,进入循环,继续刚才的操作。
注意:
那个count是用来计算素数的个数的,把它和“打印素数”放在一起。这里其他解法,如果要计数也是这么写。
因为都打印了,那肯定是确定为素数了,所以打印一个就计一个数。
要100到200遍历完了才可以输出 count 哦,要全部判断完了才知道count,所以count的打印放在循环外面。
方法三:开平方法🐾
#include<stdio.h>
#include<math.h>
int main()
{
int i = 100, j, count = 0;
for (i; i <= 200; i++)
{
int flag = 1;
for (j = 2; j <= sqrt(i); j++)
{
if (i % j == 0)
{
flag = 0;
break;
}
}
if (flag == 1)
{
count++;
printf("%d ", i);
}
}
printf("\n%d", count);
}
原理
数学事实:任意一个整数可以写成一个或多个乘积的形式。拆分成乘积的两个因子 a,b中必有一个因子小于或等于 a ∗ b \sqrt{a*b} a∗b ,如11=1*11,其中1就满足上述事实。
如果是素数,那么拆分出的两个因子中必然只有1满足上述数学事实,因为素数只能拆分为 (1*素数本身)。
所以如果在 2到 a ∗ b \sqrt{a*b} a∗b 之间找到了该数的乘积的因子,那么这个数就不是素数。
因为每个数需要比较的数字减少了,所以这种方法可以提高运行效率。
思路讲解
注意:使用开方函数sqrt()需要引头文件math.h
遍历100到200的数字。
结合了假设法的做标记的思路,其实唯一的区别就是,把用来判断的内层for循环的条件改了一下(把 j < i 变成了 j <= sqrt(i) 而已)。
还是像假设法一样,先全部标为flag=1,再逐个判断,如果不是素数,就把1改成0,最后只打印flag=1的。计数要和打印放一起,但是计数的最终结果打印,要在两层循环结束后,也就是放在循环外面。
悟了✨
判断输出类题目:遍历→逐个判断→(flag标记要被立即使用)(count计数要 放在循环外)→输出
❤️❤️❤️❤️❤️❤️ 恭喜! 恭喜! 又收了一名小弟! ❤️❤️❤️❤️❤️❤️