关于素数的埃氏筛法/区间筛法 C++(代码实现和详解)

前言

如果只对一个整数进行素性测试,通常O(n^1/2)的算法便足够了。而程序竞赛设计的主要是埃氏筛法等更高效的算法。如果要对许多整数进行素性测试,则需要利用更加高效的算法,此次以例题为媒介,介绍埃氏筛法和区间筛法。

一:埃氏筛法

eg:题目描述  

给定整数n,请问n以内有多少个素数?

n<=10^6

看到这,你可能会轻蔑的笑了,就这题,自己分分钟秒杀。但是请别急,下面介绍的埃氏算法,能让你更快解决。

埃氏算法氏和辗转相除法一样古老的算法,其大致思路如下

首先,将2~n范围内的所有数都写下来,存入一张线性表里(用一维数组实现)。其中最小的数字2是素数。将表中2的倍数都划去,当然也包括其本身。之后表中剩余的最小数字是3。它显然也是素数。那么继续将所有3的倍数划去。同理,依次类推,每次表中剩下的最小数字m都是素数,然后将表中所有的m的倍数划去。如此反复操作,便能筛出n以内的所有素数。

埃氏筛法代码实现

Code

#include
using namespace std;
const int maxn=1e6+10;
int prime[maxn];//存素数 
int is_prime[maxn];//is_prime[i]=1即表示i为素数 
int n; 
int main(){
	
	scanf("%d",&n);
	int p=0;//表示筛出来的素数的位数 
	for(int i=2;i<=n;i++)is_prime[i]=1;//从2开始初始化,0和1显然非素数非合数 
	
	for(int i=2;i<=n;i++){//开始筛 
		if(is_prime[i]){//依次遍历,每次表中is_prime[i]值仍然为1的最小的数便是一定是素数 
			prime[p++]=i;//筛出素数 
			for(int j=2*i;j<=n;j+=i)is_prime[j]=0;//倍数都划去 
		}
	}
	for(int i=0;i

相信你看完便懂。

二:区间筛法

eg: 给定整数 a和b,请问区间[a,b)内有多少个素数

a

b-a<=10^6

观察上面的例题,区间两边都是不定的。上面介绍的埃氏筛法解决了快速筛出2~n区间的所有素数。那么当左右区间都是不定时,如何才能高效筛选出素数?那么这里便要用到区间筛法。

区间筛法:

已知,对于任意合数b,其最小质因子<=根号b。如果根号b以内的素数表,便可以把埃氏筛法运用到区间[a,b)上了。也就是说,先分别做好[2,根号b)上的表和[a,b)上的表,然后从第一个表里筛得素数得同时,也将其倍数从第二个表中划去,因为b是右区间临界点,sqrt(b)显然是最大的质因子的上界,所以a~b这个区间里边的合数只可能被小于等于根下b的素数筛掉,最后剩下得便是所求区间内得素数。

区间筛法代码实现:


Code

#include
using namespace std;
#define LL long long

#define MAX_L 1000007
#define MAX_SORT_B 1000007

int  is_prime[MAX_L];
int is_prime_small[MAX_SORT_B];

//对区间[a,b)内的整数执行筛法。isprime[i - a]=1 <=> i是素数

void segment_sieve(LL a,LL b)
{
    for(int i=2; (LL)i*i < b; i++)is_prime_small[i]=1;//初始化 [2,sqrt(b)))
    
    for(int i=0; i

参考白书。

你可能感兴趣的:(算法,c++,埃氏筛法,区间筛法)