质数的判定

定义

质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数(规定1既不是质数也不是合数)。

问题

给定一个数字n,我们如何判断这个数字是不是素数?

思路

我们已经知道了素数的定义,那么我们只需要从2到n - 1依次枚举所有的数字,看看能否被n整除,如果能够被n整除,那么就说明不是质数,否则说明是质数。

解题代码

#include <stdio.h>
int main()
{
	int n, sign = 0;
	scanf("%d",&n);
	for(int i = 2; i < n; ++i)
	{
		if(n < 2 || n % i == 0)
		{
			sign = 1;
			break;
		}
	}
	if (1 == sign)
	{
		printf("不是素数\n");	
	}
	else
	{
		printf("是素数\n");
	}
	return 0;
}

这里的flag用于起标记的作用,标记是否为素数。

思考

可以发现时间复杂度是0(n)。那么我们如何优化一下?

假设一个数字 n n n,它的因子是 x x x,那么另外一个因子是 n x {n} \over {x} xn,那么两个因子一定存在一个大小关系,我们假设是 x ≤ x ≤ x n x {n} \over{x} xn ,那么我们可以得到 x ≤ x≤ x n \sqrt{n} n
注意:这里会有人这么做 : : 那我假设 n x {n} \over {x} xn ≤ x ≤x x,那么我得到 x ≥ x≥ x n \sqrt{n} n ,那该怎么继续向下分析呢?
得到这个结果不假,是真的。意味着这样做的话,得到的 x x x范围是
x ≥ x≥ x n \sqrt{n} n ,那么说明 x x x的范围是 x > = x >= x>= n \sqrt{n} n 并且 x ≤ x≤ x n n n。既然这样的话,那么另外一个因子 n x {n} \over {x} xn的范围就是 n x {n} \over{x} xn ≤ ≤ n \sqrt {n} n
经过这样的分析,我们可以发现,一个数$n$的因子一定是有一个在小于$\sqrt{n}$的范围内,一个一定是在$≥$$\sqrt{n}$的范围内。
那么既然分析到这里,我们可以这样做:

只枚举小于等于 n \sqrt{n} n 的范围内的数字,因为将这个范围内的数字枚举一遍的话,也就等效地将 n \sqrt{n} n 到n这个范围内地数字给判断了一边。比如说我们发现 n \sqrt{n} n 之前的所有数字都没有被整除,那么也就说明 n \sqrt{n} n 到n之间的数字也不会被整除,因为如果要是 n \sqrt{n} n 范围之前有的数字被整除掉的话,那么也就意味着一定有 n \sqrt{n} n 到n之间有另外一个因子和它对应。如果 n \sqrt{n} n 到n之间有数字被整除,那么也就意味着 n \sqrt{n} n 之前有另外一个因子和它对应。这里发现 n \sqrt{n} n 之前的数字没有被整除,所以意味着 n \sqrt{n} n 到n之间也没有数字被整除。

优化

我们只需要从2枚举到 n \sqrt{n} n 即可。

代码

#include <stdio.h>
int is_prime(int num)
{
	for(int i = 2; i <= num / i; ++i)//(1)
	{
		if (0 == num % i)
		{
			return 0;
			break;
		}
	}
	return 1;
}

int main()
{
	int n;
	scanf("%d",&n);
	if(!is_prime(n))
	{
		printf("不是素数\n");
	}
	else
	{
		printf("是素数\n");
	}
	return 0;
}
  1. 注意这里的写法。枚举到 n \sqrt{n} n 的话,不推荐使用sqrt(n)i * i <= num这两种写法。
  2. sqrt(n)每次都要调用库函数,那么速度就会慢一些。
  3. i * i <= n,当i很大的时候,可能会发生溢出,那么 i * i就有可能是负数,那么也会执行 i * i <= n这个语句,明显发生错误。
  4. 推荐博客中的这种写法。

写在最后

这里的优化,感觉自己写的不好。希望大家尽力理解。最后,为大家附上一张图片,帮助大家理解。

如图:
在这里插入图片描述

如果n是合数,那么它一定会有除了1和它本身之外的因子。这些因子是成对出现的,那么就如图中那样,红色的因子和蓝色的因子都是一对一对出现的。看完这个,可能会对优化那里的理解有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值