【练习-4】欧拉筛(新手向)

因为博主的能力有限,所以这一篇博客更适用于新手的快速入门,尽力做到通俗易懂,也会逐步分析。

目录

  • 欧拉筛代码
  • 代码解读
    • 1.元素的作用
    • 2.初步解释
    • 3.进一步解释
  • 使用方法

我们直接放代码然后再进行解释

欧拉筛代码

const int N = 1e7+5;
int prime[N];
bool k[N];
void ola()
{
	int cnt = 0;
	memset(k,true,sizeof k);
	for(int i=2;i<=N;i++)
	{
		if(k[i]) 	prime[++cnt] = i;
		for(int  j=1;j<=cnt;j++)
		{
			if(i*prime[j] > N)	break;
			k[i*prime[j]] = false;
			if(i%prime[j]==0)	break;
		}
	}
	k[0] = k[1] = 0;
}

代码解读

1.元素的作用

①prime数组是用来装遍历到的素数。
②k数组是为了判断遍历到的数是不是素数。//用这个
③cnt是用来记录是prime数组里的素数数量。

2.初步解释

①我们通常说欧拉筛的时间复杂度是O(N),确实如此。但是这并不是说我们只需要遍历一遍没有其他操作,同样每遍历到一个数就要有一顿操作,只是操作的复杂度很低,在N前可以忽略不计。(9*N的复杂度也是O(N))。

②bool与int一样是一种数据的类型(布尔类型),bool 的特点就是他的值只有false(0)和true(1),实际上我们也只需要这样就足够了(是/不是素数)。

③我们不需要这个函数返回任何东西,所以定义为void类型。

④函数内,memset是为了给bool函数赋初值,默认所有的数都是素数(true / 1)。

3.进一步解释

这里就是解释最核心的代码(中间的两层for循环以及里面的操作)

在第一层循环里面,如果我们遍历到的数k[i] = true 那么他就是一个素数我们把它装进prime数组里面。

※第二层循环也是欧拉筛这个‘筛’字的表现了:
① 如果 i和prime[j]的值超过了N那么就结束循环,因为之后的prime也必然会超过N,而我们需要的范围是[0,N]。(prime是由小到大遍历时放进去的所以越早放入的数值越小)

我们需要知道,除了素数以外,每个数都会有一个最小质因子(2的倍数的都是2,非2的倍数的是其他的素数)。这一点很重要
因此我们就想到了,只要把每个数和素数乘一遍把得到的数的K都标记为false(0),剩下的就是素数。
(可能会有人有疑问那他这样写,当i = 4的时候岂不是不能和还没进入prime数组的素数7相乘? 这一点不用担心,因为如果一个数是素数就会被记录到prime数组里就会有机会和更大的数去乘,eg. i = 7 ,prime[1] = 2,但是如果这个数并不是素数,那么根据上面的话,他就会有一个最小的质因子,比如4的最小质因子就是2,那么4和7的乘积就必然不会被省略,4 * 7 = 28 , 2 * 14 = 28所以不必担心)

③最后的if(i%prime[j]==0) break;可以说就是欧拉筛的核心了,他的作用就是有效的避免重复遍历,确保每一个数都是它的最小质因子最大因子相乘来把他遍历掉。
例如 45,他的因子可以是3 15也可以是5 9,但是我们要保证把他遍历掉的是15而不是9。
那么我们是怎么做到的,就是靠这句话。
想一下,当i = 9 的时候我们可以知道现在的素数里面有 2,3,5,7当他遍历掉3*9 = 27之后,(9%3==0)他接下来的遍历就是没有意义的了,比如如果继续往下走 5 * 9 = 45,很明显可以拆成 5 * 3 * 3,也就是15 * 3那么我们遍历15的时候就可以把它遍历掉,在9的时候并不需要再去遍历了!

当N=30时,可以看到由于最后一段代码(左),复杂度降低了不少,去掉最后一段代码就会重复筛选(右)。
【练习-4】欧拉筛(新手向)_第1张图片

使用方法

在main函数第一行打上ola();预处理一遍,之后不再需要其他操作。我们要判断一个数是不是素数直接判断k[i]是true 还是 false。

以上只是鄙人的拙见,如果有错误、不足之处,还请指正。

你可能感兴趣的:(XXXX,c++,素数筛)