`
wsqwsq000
  • 浏览: 673666 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

求质数的算法

    博客分类:
  • j2ee
 
阅读更多

求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));

}

}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics