素数相关(欧拉筛法个人理解)

判断素数

素数的性质,一定是6n+/-1,首先6n到6n+5可以遍历(代表)全部的数,那么因为6n能被6整除,6n+2/+4能被2整除,6n+3能被3整除,所以只剩6n+1和6n+5了。6n+5就是6n-1,所以只有在6的倍数两侧的数才有可能是素数。

bool IsPrime(int num) {
	if ( num <=3 ) return num > 1;
	if ( num % 6 !=1 && num%6 != 5 ) return false; //首先直接排除不在6n两侧的数
	//然后再正常判断是不是素数
	for ( int i = 5; i <= (int)sqrt(num); i += 6 ) //从5开始,步长6,因为因子肯定没有6n+2/3/4
		if ( num % i == 0 || num % (i + 2) == 0 ) return false; //i和i+2就是6n+5和6n+1
	return true;
}

枚举素数

开辟一个数组,把n以内的素数都枚举出来,便于计数和查找。基本思路就是把要求范围内的素数的素数倍数都挨个标记筛除,2、3、5…的倍数,剩下的就是素数——埃氏筛法。
但是有些数既是一个素数的倍数,又是另一个素数的倍数,故进一步优化就是提前筛掉重复判断的数——欧拉筛法,T=Θ(n)。

void eulerSieve(int n) {
	bool[] isPrime = new bool[n+1]; //索引值是否为素数的标记数组,初始均为素数=false
	int[] Prime = new int[n]; //存放素数的数组
	isPrime[0] = isPrime[1] = true; //先排除0和1
	int count = 0; //素数数组计数器
	
	for (int i = 2; i < n+1; i++ ) {//从2的倍数开始遍历
		if (!isPrime[i]) //如果当前i是素数
			Prime[count++] = i; //存入素数数组,之后开始筛除该素数的素数倍数
		for (int j = 0; j < count && Prime[j] * i < n+1; j++) {
			isPrime[i * Prime[j]] = true; //把n以内的当前素数i和之前素数的乘积筛除
			if (i % Prime[j] == 0) break; //欧拉筛法的关键,避免重复筛除
		}
	}
}

if (i % Prime[j] == 0) break 这行关键代码是说,如果i可以整除以一个不等于自己的素数,那么说i可以分解成该素数和另一个素数因子,那么当下次i增长到下一个素数和另一个因子的乘积时,必然会再标记新的i和该素数的乘积。
如a是能被i整除的第一个素数,b是i的另一个因子,即有i=a*b(如果b是1则跳出循环也没问题,因为到头了,i就是素数数组的最后一个),c是素数数组中a后面那个更大的素数,如果不停止for循环,则会继续把 k=i*c=a*b*c给筛除掉,但是当i在后面增长到i’=c*b时,必然在筛除的时候还会重复标记到k=i’*a=c*b*a。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值