4.朴素质数判定和质数筛法

版权声明:本文为博主原创,未经博主允许不得转载 https://blog.csdn.net/Sherry_Yue/article/details/88095877

质数检验

引题
质数指约数仅为1及其本身的自然数。比如8个最小的质数为2,3,5,7,11,13,17,19。注意,1不是质数。
请编写一个程序,输入n个整数,输出其中质数的个数。

输入:第一行输入n。接下来1行给出n个整数。
输出:输出质数的个数,占1行。
限制 1 < = b < = 10000 2 < = < = 1 0 8 1<=b<=10000,2<=给出的整数<=10^8
输入示例
6
2 3 4 5 6 7
输出实例
4

1. 初学者的简单算法

检验整数x是否为质数:检查整数x能否被2到x-1的整数整除。

bool isPrime( int x )
{
	if( x<=1 ) return false;
	for(int i=2;i<x;++i)
		if( x%i==0 )
			return false;
	return true;
}

可以得知,上述算法对于单一数据其复杂度为O(x),算法整体的复杂度与 x i ( i = 1 , 2 , , n ) x_i(i=1,2,…,n) 的总和成正比,显然无法在限制时间内输出答案。我们需要考虑一个更高效的方法。

2. 初学者优化算法
  1. 除2以外所有的偶数都不是质数,这样就能将复杂度减少一半。
  2. 在检查x时,由于x不可能被大于 x 2 \frac{x}{2} 的整数整除,这就又减少了一半复杂度。

但这些小技巧并不能撼动该算法复杂度为O(x)的本质。

3. 性质:若n为合数,则必有质数p|n,且 p &lt; = n p&lt;=\sqrt{n}

在检验质数的时候,我们可以利用“合数x拥有满足 p &lt; = x p&lt;=\sqrt{x} 的质因数p”这一性质。
举个例子,检验31是否为质数时,只需要看31能否被2到6的整数整除即可。如果7到30中存在能整除31的整数,那么2到6中必然也存在能整除31的整数,所以检查大于6的整数只是浪费资源。
利用这一性质,我们可以将检验范围从2到x-1缩小至2到 x \sqrt{x} ,算法的复杂度也就改良到了O( x \sqrt{x} )。比如x=1000000时, x \sqrt{x} =1000,此时该算法快了1000倍。

bool isprime(int x)
{
	if(x==2) return true;
	if( (x<2) || !(x&1) ) return false;//x<2或x为偶数
	int i = 3;
	while( i<=sqrt(x) )
	{
		if( x%i==0 ) return false;
		i += 2;
	}
	return true;
}
4. 埃拉托色尼筛选法

有些时候,除了检验给定整数x是否为质数的函数之外,如果能事先准备出质数数列或质数表,就可以帮助我们更有效地求解质数的相关问题。
埃拉托色尼筛选法(The Sieve of Eratosthenes)可以快速列举出给定范围内的所有质数,这个算法如下步骤生成质数表。
埃拉托色尼筛选法

  1. 列举大于等于2的整数。
  2. 留下最小的整数2,删除所有2的倍数。
  3. 在剩下的整数中留下最小的3,删除所有3的倍数。
  4. 在剩下的整数中留下最小的5,删除所有5的倍数。
  5. 以下同理,留下仍未被删除的最小整数,删除该整数的倍数,一直循环到结束。

以最小的4个质数为例,其求解过程如图。
原始表:

2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60

第一轮:

2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60

第二轮:

2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60

第三轮:

2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60

第四轮:

2 3 4 5 6 7 8 9 10
11 12 13 14 15 16 17 18 19 20
21 22 23 24 25 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48 49 50
51 52 53 54 55 56 57 58 59 60

埃拉托色尼筛选法核心代码:

#define MAX 1000000
bool isprime[MAX];
//bool型数组isprime表示质数表,
//isprime[x]为true表示x是质数,为false表示x是合数。
void eratos(int n)
{
	int i,j;
	for(i=0;i<=n;++i)//列举整数作为候选的质数
		isprime[i] = true;
	isprime[0] = isprime[1] = false;//0和1不是质数,所以删除它们
	for(i=2;i<=sqrt(n);++i)//留下i,删除i的倍数
		if( isprime[i] )
		{
			j = i+i;
			while( j<=n )
			{
				isprime[j] = false;
				j = j+i;
			}
		}
}

埃拉托色尼筛选法需要占用一部分内存空间(与待检验整数的最大值N成正比),但其复杂度只有O(N log log N)。

猜你喜欢

转载自blog.csdn.net/Sherry_Yue/article/details/88095877