筛法求【2,n】范围内的素数

290 阅读1分钟

埃氏筛法

算法:从小到大枚举素数,他们的倍数是合数,筛掉。下面是算法的实现程序:

#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
int main()
{
	int n;
	int a[10000] = {0};
	cin >> n;
	int m = sqrt(n) + 1;
	for(int i = 2;i <= m;i++)
	{
		if(!a[i])
			for(int j = i * i;j <= n;j += i)
				a[j] = 1;
	}
	int c = 0;
	for(int i = 2;i <= n;i++)
	{
		if(a[i] == 0)
		{
			cout << i << ' ';
			c++;
		}
	}
	cout << '\n' << c;
	
	return 0;
}

算法缺点: 有些合数被重复筛,如12被被素数2筛掉以后,又被素数3重复筛。 下面的欧拉算法克服了这一问题。

欧拉筛法

欧拉算法基于合数能写成最小素数p和另外一个数i的乘积,将合数筛掉。算法枚举所有i,将相应合数筛掉。 当 i % p == 0时,应采用下一个i,避免下一个素数,不是最小素因子。

#include <iostream>
using namespace std;
int main(int argc, char** argv) 
{
	int n;
	int flag[10000] = {0};
	int prime[10000] = {0};
	int c = 0;
	
	cin >> n;
	
	for(int i = 2;i <= n;i++)
	{
		if(!flag[i])
			prime[++c] = i;
		for(int j = 1;j <= c && prime[j] * i <= n;j++)
		{
			flag[prime[j] * i] = 1;
			if(i % prime[j] == 0)
				break;
		}
	}
	
	int s = 0;
	for(int i = 2;i <= n;i++)
	{
		if(flag[i] == 0)
		{
			s++;
			cout << i << ' ';
		}
	}
	cout << '\n' << s;
	return 0;
}