判定是否为素数/质数
题目如下
【例 5.9】 输入一个大于3的整数n,判定他是否为素数(质数也称素数)
我写的
int main()
{
int i = 0;
int n = 0;
scanf("%d", &n);
for (i = 1; i < n; i++)
{
if (n % 2 == 0 || n % (n - 1) == 0) // 逻辑错误
{
break;
}
//printf("%d ", n / i);
}
if (n % 2 == 0 || n % (n - 1) == 0) // 逻辑错误
{
printf("不是质数");
}
else
{
printf("是质数");
}
return 0;
}
针对我的解法进行分析
这段 C 语言代码的主要目的是判断输入的整数 n
是否为质数。
以下是对代码的详细分析:
- 在
main
函数开始,定义了两个整型变量i
和n
,并初始化为0
。 - 然后,使用
scanf
函数获取用户输入的整数,并将其存储到n
中。 - 接下来是一个
for
循环,从i = 1
开始,只要i < n
就会执行循环体。- 在循环体中,通过判断
n % 2 == 0 || n % (n - 1) == 0
来决定是否提前结束循环。如果n
能被2
整除或者能被n - 1
整除,就执行break
语句跳出循环。
- 在循环体中,通过判断
- 循环结束后,再次判断
n % 2 == 0 || n % (n - 1) == 0
。- 如果条件成立,输出
不是质数
。 - 否则,输出
是质数
。
- 如果条件成立,输出
我的写法存在的逻辑错误
- 检查是否为质数的条件不正确。一个数
n
是质数,当且仅当它不能被大于1
且小于n
的任何整数整除。在这段代码中,只检查了能否被2
和n - 1
整除,遗漏了其他可能的因子。
正确解法
#include <stdio.h>
int main() {
int n, i, isPrime = 1;
scanf("%d", &n);
if (n <= 3) {
printf("输入的数应大于 3\n");
return 0;
}
for (i = 2; i * i < n; i++) {
if (n % i == 0) {
isPrime = 0;
break;
}
}
printf("%s\n", isPrime? "是质数" : "不是质数");
return 0;
}
正解分析
-
for (i = 2; i * i < n; i++)
中i
的初始值为2
,这是因为1
肯定能整除任何数,所以从2
开始检查。 -
判断条件
i * i < n
:假设一个数
n
可以分解为两个因数a
和b
,且a <= b
,那么a * a <= n
。所以我们只需要检查到i * i < n
就可以了,超过这个范围,如果还没有找到能整除n
的数,那么n
就是质数。这样可以减少不必要的循环次数,提高效率。 -
isPrime
是一个标志变量,初始值为1
,表示我们先假设输入的数n
是质数。当在循环中找到一个能整除n
的数(即n % i == 0
)时,就将isPrime
设为0
,表示n
不是质数。最后根据isPrime
的值来输出n
是否为质数。直接使用
break
只是提前结束了循环,但并不能明确地标识最终的判断结果。使用
isPrime
变量可以更清晰、明确地记录最终的判断结论。当在循环中找到了能整除n
的数,将isPrime
置为0
。循环结束后,通过检查isPrime
的值来确定n
是否为质数。这样做的好处是:即使循环因为其他原因(比如达到了循环条件)正常结束,我们仍然可以通过
isPrime
的值得到准确的判断结果。如果仅仅使用
break
,在循环结束后,无法直接确定n
是不是质数,还需要通过其他复杂的方式来判断循环是因为找到了因数而结束,还是正常结束。使用isPrime
变量可以使代码的逻辑更加清晰和易于理解。
例如,如果 n = 15
,当 i = 3
时,15 % 3 == 0
,此时就将 isPrime
设为 0
,并结束循环,因为已经确定 15
不是质数。
答疑
问:为什么for循环里,表达式2不可以直接写成i < n
答:如果将循环条件写成 i < n
,那么循环会从 2 一直检查到 n - 1
。
这样做虽然也能判断 n
是否为质数,但是效率相对较低。因为实际上,只需要检查到 i * i <= n
就足够了。
例如,对于数 100
,如果我们已经检查到了 11
(因为 11 * 11 = 121 > 100
),就不需要再检查 12
到 99
了,因为如果 100
能被大于 11
的数整除,那么对应的另一个因数一定小于 11
,而这个小于 11
的因数在之前的循环中就应该已经被检查到了。
所以,将循环条件写成 i * i < n
可以减少不必要的检查,提高程序的运行效率。