筛法求素数

要解决的问题:给定一个正整数(n),求出所有小于等于(n)的素数

素数又称质数,其因子只有1和它自己本身;与素数相对的叫合数

1、埃拉托斯特尼筛法

#include<bits/stdc++.h>
using namespace std;
#define N 10000
#define ll long long 
int visited[N];
int prime[N];
int num=0;
// 埃式筛 
void cal(int n)
{
	memset(visited, 0, sizeof(visited));
	memset(prime, 0, sizeof(prime));
	for(int i=2; i<=n; ++i){ // 1既不是质数也不是合数 
		if(!visited[i]){
			prime[num++] = i;
			// 从i*i开始就行,因为 2*i, 3*i, ... , (i-1)*i 已经被 2,...,i-1给筛掉了 
			for(ll j=1ll*i*i; j<=n; j+=i) // 1ll表示将1换成ll类型 
				if(!visited[j]) visited[j] = 1;
		}
	}
	for(int i=0; i<num; ++i) {
		cout << prime[i] << " ";
	}
 } 
 int main()
 {
 	int n = 19;
 	cal(n);
 	return 0;
 }

筛法求素数就是先认定所有的数是素数(int visited[10000]={0}),再通过一些方法把合数踢掉((visited[k*j] = 1)),一般筛法的思想是:从2开始找,素数的倍数(1倍、2倍、3倍,,,)为合数,都筛掉(标记为访问过了)。

注意在标记i的倍数只需从i*i开始,因为小于它的i的倍数势必已经被更小的数作为倍数筛掉。同时小心i*iint

但是这个写法会让一些数被重复筛。如30,会被2、3、5作为倍数筛三遍,这样的访问太多余了。

时间复杂度(O(nlogn))

2、欧拉筛法(线性筛)

#include<bits/stdc++.h>
using namespace std;
#define N 10000
#define ll long long 
int visited[N];
int prime[N];
int num=0;
 // 线性筛
void Euler(int n)
{
	memset(visited, 0, sizeof(visited));
	for(int i=2; i<=n; ++i){
		if(!visited[i]) prime[num++] = i;
		
		for(int j=0; j<num && 1ll*i*prime[j]<=n; ++j){
			visited[i*prime[j]] = 1;
			if(i%prime[j]==0) break; // 这一句话降低了时间复杂度
									 // 这个break保证了合数只被最小质约数访问到。 
		}
	}
	for(int i=0; i<num; ++i) {
		cout << prime[i] << " ";
	}
 } 
 
 int main()
 {
 	int n = 19;
	Euler(n);
 	return 0;
 }

这个break保证了合数只被最小质约数访问到。
比如40=2*20=4*10=5*8,只有i=20时,才会在prim[j]=2的时候被访问到。
i=10时,在prim[j]=2时就已经被break了;同样的,i=8时,在prim[j]也已经break了。

快速线性筛法的特点就是不会重复筛除一个合数。它的原理是

前提是:一个合数(i=p_1*p_2*...*p_n), (p_i)都是素数(2<=i<=n), pi<=pj ( i<=j )

p1是最小的系数。这样每一个合数就有一个确定的表示方法,不会重复。(像12=2*2*3)

我们现在规定一个合数由两个数相乘得到,那么合数有两种:

  1. 素数*素数=合数
  2. 一个最小的素数*合数=合数

筛除i时:

  • 如果遇到i为素数,那么一个大的素数 i 乘以不大于 i 的素数,这样筛除的数跟之前的是不会重复的

  • 如果遇到i为合数,我们只认为合数由一个最小的素数*合数得到,也不会重复(就像12=2*6而不是12=3*4)

时间复杂度(O(n))


ps:以上代码我自己敲的,文字是以下几篇博客中摘取的整合的,如有侵权请告知。
参考链接:

https://blog.csdn.net/danliwoo/article/details/51871740

https://blog.csdn.net/sodacoco/article/details/81519269

https://blog.csdn.net/nuanxin_520/article/details/41207145


刚看到除了线性筛,还有杜教筛、min_25筛、洲阁筛...不禁感叹你他娘的算法真的博大精深啊,以后有空再慢慢研究吧,这里先挖个坑。

原文地址:https://www.cnblogs.com/VanHa0101/p/14383312.html