线性筛选素数
问题
求取范围[2,n] 之间的所有素数
方法一
方法一概述
使用数字prime[i]来标记i是否为素数。初始化prime[2…n]=1。
当处理到数字i时,若prime[i]=0,则代表2到i-1中有i的因子,因此i为合数;若prime[i]=1,则代表2到i-1中无i的因子,因此i为素数,此时筛选掉ij(2<=j<=n/i),从而筛选掉以素数i为因子的合数ij。
方法一实现
#define SIZE 1000000
int main()
{
int check[SIZE] = {0};//元素值为0代表是素数
int prime[SIZE] = {0};
int pos=0;
int flag;
for (int i = 2 ; i < SIZE ; i++)
{
if (!check[i])//如果是素数
prime[pos++] = i;
for (int j = 2*i ; j < SIZE ; j += i)
{
check[j] = 1;
}
}
printf("%.2f", (double)clock()/CLOCKS_PER_SEC);
return 0;
}
方法一问题
时间复杂度为 O ( n 2 ) O(n^2) O(n2),存在重复筛选的问题。对于6=2*3,会在i为2和3时被筛选掉。
方法二——线性筛法
方法二概述
目标:对于
m
=
p
i
a
∗
p
j
b
∗
.
.
.
p
k
c
m=p_i^{a}*p_j^{b}*...p_k^{c}
m=pia∗pjb∗...pkc,其中
p
i
<
p
j
<
.
.
.
p
k
p_i<p_j<...p_k
pi<pj<...pk,为了避免重复筛选,仅使用
p
i
p_i
pi来筛选数
m
m
m,称
p
i
p_i
pi为最小素因子。
策略:
使用prime数组来记录当前所得到的素数,使用is_prime[i]来标记数i是否被筛选。
对于当前数m,若其没有被筛选,则将其加入prime数组中。无论m是否为素数,遍历prime数组,来筛选掉以
p
r
i
m
e
[
i
]
prime[i]
prime[i]为最小素因子且等于
m
∗
p
r
i
m
e
[
i
]
m*prime[i]
m∗prime[i]的合数,为了确保
m
∗
p
r
i
m
e
[
i
]
m*prime[i]
m∗prime[i]是以prime[i]为最小合数的,因此若出现
p
r
i
m
e
[
i
]
∣
m
prime[i]|m
prime[i]∣m(即m中含有素因子
p
r
i
m
e
[
i
]
prime[i]
prime[i]),将不在考虑使用
m
∗
p
r
i
m
e
[
j
]
(
j
>
i
)
m*prime[j](j>i)
m∗prime[j](j>i)来进行后续的筛选(因为此时的最小素因子为m的最小素因子
p
r
i
m
e
[
i
]
prime[i]
prime[i]而非
p
r
i
m
e
[
j
]
prime[j]
prime[j])。
覆盖性证明:
上述策略保证了使用最小素因子
p
r
i
m
e
[
i
]
prime[i]
prime[i]来进行筛选,并通过prime[i]|m来避免了重复的筛选,即满足了一个数仅筛选一次的目标。
对于筛选的范围能否覆盖
[
1...
n
]
[1...n]
[1...n]中的所有数,由于m是从1到n遍历的,因此会考虑到所有
m
∗
p
r
i
m
e
[
i
]
(
m
=
1...
n
)
m*prime[i](m=1...n)
m∗prime[i](m=1...n)的情况(当
p
r
i
m
e
[
i
]
>
m
m
i
n
prime[i]>m_{min}
prime[i]>mmin时不予筛选,
m
m
i
n
m_{min}
mmin代表m的最小素因子,因为这不满足
p
r
i
m
e
[
i
]
prime[i]
prime[i]为
m
∗
p
r
i
m
e
[
i
]
m*prime[i]
m∗prime[i]为最小素因子的定义),因此所有以prime[i]为最小素因子的合数都会被筛选掉。
操作过程示例:
方法二实现
#include<iostream>
using namespace std;
#define NUM 20
void get_prime() {
int is_prime[NUM] = { 0 };
int prime[NUM];
int prime_num = 0;
for (int m = 2; m < NUM; m++) {
//数m没有被筛选过
if (!is_prime[m]) {
prime[prime_num++] = m;
}
//筛选掉以prime[i]为最小素因子的合数m*prime[i]
for (int i = 0; i < prime_num; i++) {
if(m*prime[i]<NUM) is_prime[m * prime[i]] = 1;
if (m % prime[i] == 0) break;//m*prime[j](j>i)的最小素因子为m的最小素因子prime[i]而非prime[j],因此跳出循环
}
}
//打印输出
for (int i = 0; i < prime_num; i++) {
cout << prime[i] << " ";
}
cout << endl;
}
int main() {
get_prime();
}