求质数的算法

本文介绍了三种求解质数的方法,包括最笨方法、优化后的平方根法及高效的筛法。并通过实例详细解释了每种算法的工作原理及其优劣。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

求i到j之间的所有质数

最笨的一种方法是把i到j之间的每一个数n,都拿出来,挨个循环用n除以从2到n-1的所有整数,如果期间有一个能整除,那么n是合数,继续下一个。

第二种算法效率比这个就高了很多,利用的是一个定理——如果一个数是合数,那么它的最小质因数肯定小于等于他的平方根。比如,50,它的最小质因数是2,它的平方根是7.07xxx,2<=7.07xxx。大家可以多找几个合数试一下。也可以用反证法证明。


   设a = bq,因为a是合数,则b和q都是大于1的整数.      
   又设q是a的最小质因数,即b>=q.      
   如果q<=根号a   不成立,则必有 q>根号a,此时更有b > 根号a,于是    
a = bq > 根号a·根号a =   a      
   出现矛盾,故q <=根号a      
   证毕.  

利用这个原理,只需将i和j之间得某个数n取出,并用循环将n除以从3到根号n之间的所有整数(2的不在考虑范围内,因为所有除2以外的偶数都是合数),如果期间存在一个数可以整除,那n为合数,否则为质数。

第三种方法是效率最高的一种方法。首先建立一个布尔型1维数组a,长度为j-i,初始值为true。首先用第二种方法求得i、j之间的第一个质数m。求得m以后,将所有小于i的m的倍数所在的数组(即a[m的倍数-i])位置全部设为false。然后进行下一步,从n=m++开始,如果a[n-i]已经被设置为false,则n++,直到出现首个为true的位置p,再将所有小于i的p的倍数所在的数组位置置为false。继续下一步,直到n>根号j为止,这样所有为true的数组id(如果i=1则0除外,id从1开始)+i 即为质数。

说的比较复杂,举个例子。例如要查找2-100之间的质数,首先2是质数,把2的倍数去掉(比如4,6,8,...,100,对应的数组位置是a[m-2]即a[2],a[4],a[6],...,a[98],将这些位置设为false);进行下一步,此时3没有被去掉(a[2]=true),可认为是质数,所以把3的倍数去掉(a[5]a[8]a[11],...,a[98]=false);再到5,再到7,7之后呢,因为8,9,10刚才都被去掉了,而100以内的任意合数的最小质数因子肯定小于等于10(100的开方),所以,去掉,2,3,5,7的倍数后剩下的都是质数了。最后只要将a[id]中所有等于true的id值加上i输出即可。按照这个例子是id+2,比如0+2,1+2,3+2,...
相对来说这种算法求1到n之间的质数实现起来比较简单,如果是求任意两个数之间的质数,逻辑上会比较复杂。但是,效率的确提高了很多很多。
 

 
代码实现如下:
 
一、利用BitSet(筛法) 
import java.util.*;

public class BitSetTest{

public static void main(String[] args){

BitSet sieve=new BitSet(1024);

int size=sieve.size();

for(int i=2;i< size;i++)

sieve.set(i);

int finalBit=(int)Math.sqrt(sieve.size());



for(int i=2;i< finalBit;i++)

if(sieve.get(i))

for(int j=2*i;j< size;j+=i)

sieve.clear(j);



int counter=0;

for(int i=1;i< size;i++){

if(sieve.get(i)){

System.out.printf("%5d",i);

if(++counter%15==0)

System.out.println();

}

}

}

}

--------------------------------------------------------------------

C:\java>java BitSetTest
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  101 103 107 109 113
127 131 137 139 149 151 157 163 167 173 179 181 191 193 197
199 211 223 227 229 233 239 241 251 257 263 269 271 277 281
283 293 307 311 313 317 331 337 347 349 353 359 367 373 379
383 389 397 401 409 419 421 431 433 439 443 449 457 461 463
467 479 487 491 499 503 509 521 523 541 547 557 563 569 571
577 587 593 599 601 607 613 617 619 631 641 643 647 653 659
661 673 677 683 691 701 709 719 727 733 739 743 751 757 761
769 773 787 797 809 811 821 823 827 829 839 853 857 859 863
877 881 883 887 907 911 919 929 937 941 947 953 967 971 977
983 991 997 1009 1013 1019 1021
C:\java>

二、第二个程序

作者:wolfigo



/*个人认为比较经典的一段求任意范围质数的小程序*/

/*布尔数组isPrime[],其中的元素为true时,表示为质数*/

/*

Demo Test Data: 打印1-10之间的数是否是质数

测试结果:  false, true, true, false, true, false, true, false, false, false

(  1      2      3     4      5     6     7     8      9       10  )

其它范围的测试结果以此类推。

*/

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

public class Sieve

{

private static boolean[] sieve(int range)

{

boolean[] isPrime = new boolean[range + 1];

for (int i = 1; i < isPrime.length; i++)

{

isPrime[i] = true;

}

isPrime[1] = false;

int n = (int) Math.ceil(Math.sqrt(range));

for (int j = 1; j <= n; j++)

{

if (isPrime[j])

{

for (int k = 2 * j; k <= range; k += j)

{

isPrime[k] = false;

}

}

}

return isPrime;

}

private static int findLargest(boolean[] isPrime)

{

int largest = isPrime.length - 1;

for (; !isPrime[largest]; largest--);



return largest;

}

public static void main(String[] args)

{

BufferedReader input = new BufferedReader(new InputStreamReader(

System.in));

int param = 0;

try

{

param = Integer.parseInt(input.readLine());

}

catch (NumberFormatException e)

{

System.out.println("Invalid Argument.");

}

catch (IOException e)

{

e.printStackTrace();

}

boolean[] isPrime = sieve(param);

for (int i = 1; i < isPrime.length; i++)

{

System.out.print(isPrime[i] + ", ");

}



System.out.println();

System.out.println(findLargest(isPrime));

}

}
### 素算法概述 素是指大于1的自然中除了1和其本身外无法被其他自然整除的。对于计算素,存在多种不同的算法来判断一个给定的字是否为素以及寻找一定范围内的所有素。 #### 判断单个是否为素的方法 一种常见的用于检测单一值是否为素的方式是从2开始尝试除尽该直到平方根为止。如果没有任何因子可以完全划分这个,则认为它是质数。下面是一个简单的函实现[^4]: ```javascript const isPrime = (number) => { if (number <= 1) return false; if (number === 2) return true; if (number % 2 === 0) return false; for (let j = 3; j * j <= number; j += 2) { if (number % j === 0) { return false; } } return true; }; ``` 此代码片段定义了一个`isPrime()`函用来验证传入参`number`是不是素。当遇到偶时立即返回false优化性能;而对于奇则仅需测试能否被小于等于它平方根的小于自身的奇所整除即可得出结论。 #### 找出指定范围内所有的素 为了找出某个区间内全部的素,可以通过遍历每一个可能成为候选者的正整并调用上述辅助函来进行筛选: ```javascript function findPrimesInRange(maxNumber){ var primes=[]; for(let num=2;num<=maxNumber;num++){ if(isPrime(num)){ primes.push(num); } } return primes; } console.log(findPrimesInRange(50)); // 输出 [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] ``` 这段程序展示了如何利用之前提到过的`isPrime()`逻辑,在给定的最大界限之内收集所有符合条件的素,并最终打印出来作为结果列表的一部分。 #### 使用埃拉托斯特尼筛法解大量素 更高效的解决方案之一是采用古老的埃拉托斯特尼筛法(Sieve of Eratosthenes),这种方法特别适合处理较大规模的据集: ```python def sieve_of_eratosthenes(limit): limitn = limit+1 not_prime = set() primes = [] for i in range(2, limitn): if i in not_prime: continue for f in range(i*2, limitn, i): # 将i的所有倍标记成合 not_prime.add(f) primes.append(i) return primes print(sieve_of_eratosthenes(50)) # 结果: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] ``` 通过预先创建一个布尔组表示哪些位置上的索引对应着潜在的素候选人,随后逐步消除那些已经被确认是非素的位置,从而大大减少了不必要的重复运算次
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值