要解决的问题:给定一个正整数(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*i
爆int
。
但是这个写法会让一些数被重复筛。如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)
我们现在规定一个合数由两个数相乘得到,那么合数有两种:
- 素数*素数=合数
- 一个最小的素数*合数=合数
筛除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筛、洲阁筛...不禁感叹你他娘的算法真的博大精深啊,以后有空再慢慢研究吧,这里先挖个坑。