线性筛法求素数的原理与实现

2 篇文章 0 订阅
1 篇文章 0 订阅

何为线性筛法,顾名思义,就是在线性时间内(也就是On))用筛选的方法把素数找出来的一种算法,没用过线性筛素数法的人可能会奇怪,用遍历取余判定素数不是也是线性时间的吗,没错,但是确切的说线性筛法并不是判定素数的,而是在线性时间内求出一个素数表,需要判定是否是素数的时候只要看该数是否在表内就可以瞬间知道是不是素数

比如想求10000以内的素数,定义表int a[10000],进行线性筛选后,a[n]的值就代表n是不是素数,a[n]如果是1,就代表n是素数,a[n]如果是0,就代表n不是素数,这就是查表。再判定其他的素数也是一样,不用再做任何计算。

而如果用遍历取余,那么每判定一个数都要从头开始再遍历一遍,而线性筛法只在开始一次性运算完,以后只要查表即可,查表通常只需要1条语句。所以如果你的程序从始至终只需要判定那么几次素数那么用遍历取余即可,但是如果需要多次判定素数,而且这个数还不是很小的话,那么线性筛法就会体现出巨大的优越性来。

线性筛法的核心原理就是一句话: 每个合数必有一个最因子(不包括它本身) ,用这个因子把合数筛掉,还有另一种说法(每个合数必有一个最小素因子,用这个因子筛掉合数,其实都一样,但是我觉得这种方法不太容易说明,这种方法我会在最后给出简略说明)。这个很容易证明:这个小学就知道合数一定有因子,既然是几个数,就一定有最大的一个。最大因子是唯一的,所以合数只会被它自己唯一的因子筛掉一次,把所有合数筛掉后剩下的就全是素数了。

先假设一个数i,一个合数tit最大的因数,t显然可能并不唯一(例如3045的最大因数都是15)。那么如何通过i知道t呢,t必然等于i乘以一个比i小的素数。先来说这个数为什么一定要比i小,这很显然,如果是i乘上一个比它大的素数,那么i显然不能是t最大的因子。再来说为什么要是素数,因为如果乘上一个合数,我们知道合数一定可以被分解成几个素数相乘的结果,如果乘上的这个合数x=p1*p2*……,那么t = i * x = i * p1 * p2……很显然p1* i也是一个因数,而且大于i。所以必须乘上一个素数。

i小的素数一定有不少,那么该乘哪一个呢,既然t不唯一,那么是不是都乘一遍呢?很显然不行,虽然t不唯一,但全乘一遍很显然筛掉的数的数量远远超过合数的数量。我们先给出结论:

任意一个数i = p1*p2*……*pnp1p2、……pn都是素数,p1是其中最小的素数,

i * M的积(显然T就成了一个合数),也就是T = i * M,(M是素数,并且M<=p1,那么T的最大的因数就是i

是的,乘上的数要小于等于i最小的质因数。

为什么呢?我来证明这一点。

假设i可以表示为素数乘积:i = p1*p2*...pn,其中i最小的素因数是p1,设M是素数,并且大于i最小的素因数p1。设i*M=y,显然同时y=M * p1*p2*……pn因为M>p1,显然

M*p2*……pn要大于i=p1*p2*……pnM*p2*……pn又很显然是y的一个因数,那么y的最大因数就不是i。由此说明了了上面给出的结论。

本文给出的证明方法并不是很严格,很不严密,但是本文只是想解释线性筛素数的算法,并不是想严格证明,如果想看严格证明请看数论中的证明。另上面提到的线性筛素数的另一种说法,其实到这里读者应该差不多明白了,任何一个合数都可分解为一个素数和另一个数(不一定是素数还是合数)的乘积。我们既然找到了这个合数最大的因数,那么根据上面结论里另一个乘上的素数必然就是他的最小素因数。另一种说法只不过是换一个说法罢了。

最后我们就可以得出结论:对于每一个数i,乘上小于等于i的最小素因数的素数,就得到以i为最大因数的合数。设有一个数t,只要将所有以比t小的数为最大因数的合数筛去,那么比t小的数里剩下的就只有素数了。这就是线性筛法求素数的方法。

c++实现线性筛10000以内素数

	//author: bjr
	#define N 10000
	int flag[N+1],prime[N+1],pnum;
	/*
	flag[n] 表示n是否是素数,1是素数,0不是
	prime   中是所有的素数按从小到大排列、
	pnum  表示素数的个数
	*/
	void CreatePrime(){
		pnum=0;//初始化没有素数
		//先将所有数看做素数,然后开始筛选
		for(int i=0; i<=N; i++){
			flag[i]=1;
		}
		//遍历筛去所有最大因数是i的合数
		for(int i=2; i<=N; i++){
			if(flag[i]==1){
			//把素数记录下来
				p[pnum++]=i;
			}
			//遍历已知素数表中比i的最小素因数小的素数,并筛去合数
			for(int j=0; j<pnum && p[j]*i<=N; j++){
			//筛去合数
				flag[p[j]*i]=0;
				if(i%p[j]==0)
				//找到i的最小素因数
					break;
			}
		}
}


  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 线性筛是一种常用的求素数的方,它的思想简单且高效。下面是使用Java语言实现线性筛求素数的代码: ```java import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class LinearSieve { public static List<Integer> getPrimes(int n) { boolean[] isComposite = new boolean[n + 1]; List<Integer> primes = new ArrayList<>(); for (int i = 2; i <= n; i++) { if (!isComposite[i]) { primes.add(i); } for (int j = 0; j < primes.size() && i * primes.get(j) <= n; j++) { isComposite[i * primes.get(j)] = true; if (i % primes.get(j) == 0) { break; } } } return primes; } public static void main(String[] args) { int n = 100; List<Integer> primes = getPrimes(n); System.out.println("从 2 到 " + n + " 的素数为:"); for (int prime : primes) { System.out.print(prime + " "); } } } ``` 以上代码中,我们使用了一个布尔数组`isComposite`来标记是否为合数。初始时,将所有数都标记为非合数。然后从2开始,遍历到n,如果某个数i是合数,则跳过;如果是素数,则将其加入到素数列表中,并标记它的倍数为合数。遍历结束后,我们得到了从2到n的所有素数。 在main函数中,我们设置n为100,调用`getPrimes`函数获取从2到100的素数,并打印出来。 运行结果为:从 2 到 100 的素数为:2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97。 ### 回答2: 线性筛是一种高效地筛选出一定范围内的素数的算。下面是用Java实现线性筛求素数的代码: ```java import java.util.*; public class LinearSieve { public static List<Integer> sieve(int n) { boolean[] isPrime = new boolean[n + 1]; Arrays.fill(isPrime, true); // 将所有数初始化为素数 List<Integer> primes = new ArrayList<>(); for (int i = 2; i <= n; ++i) { if (isPrime[i]) { primes.add(i); // 将素数加入结果列表 } for (int j = 0; j < primes.size() && i * primes.get(j) <= n; ++j) { isPrime[i * primes.get(j)] = false; // 将当前素数倍数标记为非素数 if (i % primes.get(j) == 0) { break; // 若当前数为素数倍数,跳出内层循环 } } } return primes; } public static void main(String[] args) { int n = 100; // 范围上限 List<Integer> primes = sieve(n); System.out.println("范围[2, " + n + "]内的素数有:"); for (int prime : primes) { System.out.print(prime + " "); } } } ``` 通过线性筛,我们首先将所有数初始化为素数,然后从2开始,将每个素数的倍数标记为非素数,直到筛选结束。最后,将筛选出的素数存入结果列表中。在上述代码中,我们以100为例,调用`sieve`方求解范围内的素数,并输出结果。 当我们运行上述代码时,将会得到范围[2, 100]内的素数列表: ``` 范围[2, 100]内的素数有: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ``` 以上就是使用Java实现线性筛求素数的代码及结果。 ### 回答3: 线性筛是一种用于求解素数的算,可以高效地找出某一个范围内的所有素数。下面是使用Java语言实现线性筛求素数的代码: ```java import java.util.ArrayList; import java.util.List; public class PrimeNumbers { public static List<Integer> getPrimeNumbers(int n) { List<Integer> primeNumbers = new ArrayList<>(); boolean[] isComposite = new boolean[n + 1]; for (int i = 2; i <= n; i++) { if (!isComposite[i]) { primeNumbers.add(i); } for (int j = 0; j < primeNumbers.size() && i * primeNumbers.get(j) <= n; j++) { isComposite[i * primeNumbers.get(j)] = true; if (i % primeNumbers.get(j) == 0) { break; } } } return primeNumbers; } public static void main(String[] args) { int n = 100; List<Integer> primeNumbers = getPrimeNumbers(n); System.out.println("在[2, " + n + "]范围内的素数有:"); for (int number : primeNumbers) { System.out.println(number); } } } ``` 这段代码使用了一个布尔数组isComposite来记录某个数是否为合数(非素数),初始时假设所有数都是质数,然后从2开始遍历到n,如果某个数i没有被标记为合数,就将其添加到素数列表中,并将i与已有的质数依次相乘,将其标记为合数。 运行以上代码,可以求解出2到100之间的所有素数。输出结果如下: ``` 在[2, 100]范围内的素数有: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 ``` 通过线性筛,我们可以高效地找到某个范围内的素数,而不需要遍历所有的数进行判断。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值