欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

素数检测算法

程序员文章站 2024-03-16 16:48:52
...

前言

今天做ACM的时候,遇到了素数的检测,检测一个范围内的素数的时候,如果用最简单的那种方法,超时严重,因此学习了一个新的素数检测算法——素数筛选法,这里也是跟大家分享一下

素数

素数的定义

一个大于1的整数,如果不能被除1和它本身之外的其它正整数整除,则是素数(又称质数)

合数的定义

一个大于1的整数,如果不是素数则是合数。其中能整除这个数的正整数叫做约数,不等于1也不等于合数本身的约数叫做非平凡约数。

注意:

1既不是素数也不是合数

检测素数

所谓素数检测,就是给定任意一个大于1的整数,判断这个整数是否为素数。

因子检测法

方法:就是从2到n-1一个个的拿来尝试,看能否整除n,如果存在能够整数n的(找到一个因子),则n不是素数,否则认为n是素数。实际,是不需要试探到n-1的,只要的n的二次方根即可,原因是:
设n = a * b,且a、b均为n非平凡约数,显然a > n的二次方根和b > n的二次方根不可能同时成立,因为同时成立时 a * b就会大于n,所以如果n存在非平凡约数,至少有一个小于等于n的二次方根,因此只要遍历到n的二次方根即可。

因子检测的实现代码如下(c):

int isPrime(int n)
{
	int i, flag;
	flag = (n <= 1)? 0 : 1;
	
	for(i = 2; i <= sqrt(n); i ++)
	{
		if(n % i == 0)
		{
			flag = 0;
			break;
		}
	}
	return flag;
}

测试结果:

素数检测算法

时间复杂度:

很明显,因子检测算法的时间复杂度是0(n的二次方根),一般来说,这个时间复杂度已经很牛叉了,但是如果我要求n以内所有的素数集合,那时间复杂度瞬间就到了n * n的二次方根,这个对于n很大时是不可忍受的

素数筛选法

利用素数因子检测法去超找n以内的所有素数,时间复杂度太高,不可忍受,因此这里介绍另外一种算法,素数筛选法,可以大大的节省时间,带来的直接功效是九度acm关于素数检测的题我瞬间ac,用素数因子检测基本都是wa。

原理:

当i是素数的时候,则i的所有倍数必然是合数。如果i已经判断不是素数了,那么找到i后面的质数来把这个质树的倍数筛掉。

求20以内素数的筛选过程:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
第一步,因为所有的偶数和0,1必然不是质数,则将这些数的对应的value标记为flase,其余为true。
第二步:
i = 3,由于prime[3] = 1,则prime[6],prime[9],prime[12],prime[15],prime[18]均标记为0;
i = 4,由于prime[4] = 0,则continue,不做处理;
i = 5 > sqrt(20),算法结束

时间复杂度:

这个时间复杂度由于我的数学知识有限,也没法把计算过程解释出来,总之确实是很快,至于为什么i= 5就结束了,原因跟素数因子法里面的原理是一样的,因为n的因子必然有一个是小于等于n的二次方根的。

素数筛选法实现代码:

void getPrimeArray(int *prime)
{
	int i, j;
	//初始化素数标识数组
	for(i = 0; i < max; i ++)
	{
		if((i == 2 || i % 2 != 0) && i != 1)
		{
			prime[i] = 1;
		} else
		{
			prime[i] = 0;
		}
	}
		
	//进行素数的筛选
	for(i = 2; i * i < max; i ++)
	{
		if(prime[i])
		{
			for(j = 2 * i; j < max; j += i)
			{
				prime[j] = 0;
			}
		}
	}

}

参考资料