欧拉筛法

前言

  • 对于寻找质数,即使用sqrt()缩小范围,查找起较多的数据时还是效率很低,无疑就是重复的过多,为此学习了埃氏筛法和欧氏筛法。

埃氏筛 O(nlog(logn))

  • 基本思想:从2开始,将每个质数的倍数标记为合数,达到筛选质数的目的。

  • 代码

 /**
	 * @param n 查询n以内的质数(不包括n)
	 * @return primeCount 质数个数
	 * @author 许钱洲
	 */
	public static int PrimeCount(int n) {
		int primeCount = 0;// 记录质数个数
		int[] prime = new int[n];// 存质数
		Boolean[] isPrime = new Boolean[n];// true表示i是素数

		for (int i = 0; i < n; i++) {
			isPrime[i] = true;// 初始化
		}
		isPrime[0] = isPrime[1] = false;// 0,1不是素数

		// 0,1不是素数,直接从2开始
		for (int i = 2; i < n; i++) {
			// 如果i是质数
			if (isPrime[i]) 
				// 记录质数个数并存入prime数组中
				prime[primeCount++] = i;
				// 找到所有i的倍数,布尔值置为false
			for (int j = 2 * i; j < n; j += i) {
				isPrime[j] = false;
			}
			
		}
		return primeCount;
	}

缺点

  • 对某些数还是会进行重复的筛选,比如12会被26筛也会被34筛,我们考虑进一步的优化。

欧氏筛法 O(n)

  • 基本思想:
  1. 拿12来举例解释,可以更好的理解:12可以拆成2 * 6和3 * 4。
  2. 当到2时,素数数组prime中存了一个2,那么2 * 2筛掉4,然后prime中存入3,筛掉3 * 2=6和3 * 3=9,然后到4,筛掉4 * 2 =8,此时4 % 2==0所以不再继续下去,不筛掉12,break跳出循环,而12是到6 * 2那里才筛掉的,这样就避免了埃氏筛的重复。
  3. 而为什么要在i % prime[j] == 0时跳出循环呢,因为4不是12的最小质数,而欧氏筛的核心就是:一个质数 * 一个合数 = 一个更小的质数 * 一个更大的合数。
  4. 一个质数 * 一个合数 = 一个更小的质数 * 一个更大的合数这一步可以这么证明:
    i = p * q(p为i的最小质因子)①
    i * prime[j+1]=p * q * prime[j+1]
    = p * (q * prime[j+1])
    prime[j+1]是一个质数,p也是一个质数,而且由①可知p < prime[j+1],所以应该通p这个位置去找到要筛的数,而不是在prime[j+1]的位置去筛,所以要break。
  • 代码
/**
	 * @param n 查询n以内的质数(包括n)
	 * @return primeCount 质数个数
	 * @author 许钱洲
	 */
	public static int PrimeCount(int n) {
		int primeCount = 0;// 记录质数个数
		int[] prime = new int[n];// 存质数
		Boolean[] isPrime = new Boolean[n + 1];// true表示i是素数

		for (int i = 0; i <= n; i++) {
			isPrime[i] = true;// 初始化
		}
		isPrime[0] = isPrime[1] = false;// 0,1不是素数

		// 0,1不是素数,直接从2开始
		for (int i = 2; i <= n; i++) {
			// 如果i是质数
			if (isPrime[i])
				// 记录质数个数并存入prime数组中
				prime[primeCount++] = i;
			// 找到所有i的倍数,布尔值置为false
			for (int j = 0; j < primeCount && i * prime[j] <= n; j++) {
				isPrime[i * prime[j]] = false;
				if (i % prime[j] == 0)// 当取得的倍数取余素数为0时,不再继续
					break;
			}
		}
		return primeCount;
	}

优点

避免了埃氏筛的重复,效率更高

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值