素数筛选法

埃拉托斯特尼筛法

质数的倍数必然不是质数,所以遇到质数,就把他的倍数划掉

const int N = 10001;
//false为质数,true为合数
bool visit[N];
void  eratosthenesSieve() {
	//0,1特判
	visit[0] = visit[1] = true;
	for (int i = 2; i*i < N; ++i) {
		//i是质数
		if (!visit[i]) {
			//划掉他的倍数
			for (int j = i * i; j < N; j += i) {
				visit[j] = true;
			}
		}
	}
}

也可以只筛选奇数

const int N = 10001;
//false为质数,true为合数
bool visit[N];
void eratosthenesSieve() {
    //0,1特判
    visit[0] = visit[1] = true;
    //筛选掉偶数
    for (int i = 4; i < N; i += 2) {
        visit[i] = true;
    }
    for (int i = 3; i * i < N; i += 2) {
        //i是质数
        if (!visit[i]) {
            //划掉他的倍数
            for (int j = i * i; j < N; j += i) {
                visit[j] = true;
            }
        }
    }
}

时间复杂度O(nloglog n)

欧拉筛选法

让每一个数字只被他的最小素数筛选一遍

const int N = 10001;
//false代表质数,true代表合数
bool visit[N];
//质数个数
int cnt;
//质数
int prime[N];
void eulerSieve() {
	visit[0] = visit[1] = true;
	for (int i = 2; i < N; ++i) {
		//是质数
		if (!visit[i]) {
			prime[cnt] = i;
			++cnt;
		}
		for (int j = 0; j < cnt&&i*prime[j] < N; ++j) {
			//用prime[j]筛选
			visit[i*prime[j]] = true;
			//关键
			if (i%prime[j] == 0) {
				break;
			}
		}
	}
}

对于i%prime[j]==0就break的解释:

因为i%prime[j]==0

所以i=k*prime[j]

如果不break

当筛选后面的数字i*prime[r]就会被prime[r]筛选掉

但是i*prime[r]=k*prime[j]*prime[r]=prime[j]*t

prime[j]<prime[r]

就不是被最小素数筛选掉了

应该等到i=t=k*prime[r]时再筛选掉

这样才是用最小素数筛选

时间复杂度O(n)

Sundaram筛选法

也叫森德拉姆素数筛法

只能筛奇质数,所以2要特判

原理:

构造数阵

第i行首项是4+3(i-1),公差2i+1的等差数列

4710131619...
71217222732...
101724313845...
13·2231404958...
162738496071...
193245587184...
.....................

若n在数阵上则2n+1不是质数,否则2n+1是质数

证明:

先证明:若n在数阵上则2n+1不是质数

第i行j列的元素:a_{ij}=4+3\left(i-1 \right )+\left(j-1 \right )\left(2i+ 1 \right )= i+j+2ij

2n+1= 2\left(i+j+2ij \right )+1= \left(2i+1 \right )\left(2j+1 \right )为合数

所以如果若n在数阵上则2n+1不是质数

接下来证明:若n不在数阵上,则2n+1是质数

等价的逆否命题为:若2n+1不是质数,则n在数阵上

2n+1= mn

m,n为奇数

\\ \therefore m=2p+1,n=2q+1\\ \therefore 2n+1= \left(2p+1 \right )\left(2q+1 \right )=2\left(2pq+p+q \right ) +1\\ \therefore n=2pq+p+q

n符合数阵的通项,所以n在数阵上

即证明了若2n+1不是质数,则n在数阵上

原命题:若n不在数阵上,则2n+1是质数 也成立

算法具体流程:

我们判断是不是素数主要就是对于任意的奇数2n+1,判断n在不在数阵上

所以我们要把数阵上的数字筛选掉

由于i+j+2ij在数阵上,所以就暴力循环筛选掉

const int N = 10000000;
//数阵,false表示不在数阵上,true表示在数阵上
bool visit[N / 2];
void sundaramSieve() {
	//只要筛到(n-1)/2就可以了
	int m = N / 2;
	for (int i = 1; i <= m; ++i) {
		//i<=j,p是数阵上的数字
		int j = i, p = i + j + 2 * i*j;
		//最小的比m大就可以结果了
		if (p > m)break;
		while (p <= m) {
			//p在数阵上
			visit[p] = true;
			++j;
			p = i + j + 2 * i*j;
		}
	}
}
//判断是否是质数
bool isPrime(int n) {
	//0,1不是质数
	if (n < 2)return false;
	//2是质数
	else if (n == 2)return true;
	//大于2的偶数也不是质数
	else if ((n & 1) == 0)return false;
	//在数阵就不是质数,否则是质数
	else return !visit[(n - 1) / 2];
}

时间复杂度O(n)

Atkin筛选法

有空了再看看,时间复杂度O(n)

https://en.wikipedia.org/wiki/Sieve_of_Atkin

对比:

耗时:Sundaram < 欧拉 = Atkin < 埃拉托斯特尼。

空间占用:Sundaram < 埃拉托斯特尼 = Atkin < 欧拉。

参考:

https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

Eratosthenes筛选法与欧拉筛选法(整理)_铭霏的博客-CSDN博客

利用辛达拉姆筛进行素数判定_yutianzuijin的博客-CSDN博客

寻找质数的方法克 - 道客巴巴

https://en.wikipedia.org/wiki/Sieve_of_Sundaram

https://en.wikipedia.org/wiki/Sieve_of_Atkin

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nightmare004

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值