埃式筛法筛选素数 PAT1013

内容摘要:

  1. 明确素数到底是啥数。
  2. 埃式筛法是干嘛用的。
  3. 利用java实现埃式筛法的思路。
  4. 利用埃式筛法解决PAT_1013_B 题。
  5. 筛法的改进。

素数(prime number)到底是啥数:

定义:

   在大于1的自然数中,除了1和它本身以外不能再被其他数所整除。

 

实例化定义:

  • 3是素数,因为它不可以被除了“1”以及自身“3”之外的数所整除。
  • 10不是素数,因为它除了“1”以及自身“10”之外,还可以被"2",“5”等数字所整除,所以他不是素数。我们也叫他“合数”(composite number)。

需要注意:

  • 2是最小的素数。
  • "素数"和"质数"是同一样东西。

埃式筛法是干什么用的:

  作用:

              从一堆自然数里面,找出这一堆自然数里面的所有的素数。

       实例化:

  •  前提:a[]={1,2,3,4,5,6,7,8,9...29},prime[]={}。
  •  通过:  埃式筛法从数组a中筛选出所有的素数,并且把他们放进数组prime[]中。
  •  得到:prime[]={2,3,5,7,11,13,19,23,29}。

利用java实现埃式筛法的思路:

  首先明确算法主要的依据以及两个前提:

       主要的依据:任何一个合数,一定有比他小的素数因子。(大家可以利用小时候学的分解自然数的过程去理解一下这句话)

  • 默认2是已知的最小的素数
  • 任何素数的倍数都不是素数,比如已经"2"是素数,但是2的倍数,例如4,6,8,10,12...都一定不是倍数,因为"倍数"就是可以整除这个数的因子。             

 

下面是寻找n = 50以内的所有素数的实例:

我们首先建立了一个数字由2到50的数组。  

 

 然后我们确定2是素数,所以我们标记了所有2的倍数为非素数。

 

   因为3没有在上一步被标记,所以我们得出3是素数,然后我们标记所有3的倍数为非素数

 

 然后我们来到没有被标记的数字5,然后标记所有5的倍数为非素数

 

我们继续,然后得到

 

所以,素数应该是这里面没有被标记的元素:2,3,5,7,11,13,17,19,23,29,31,37,41,43,47.

(以上Figure由Krishan Kumar提供)

 

 转化成代码的几个关键部分:

1.利用boolean类型的素组去标记非素数

2.算法由嵌套的两层循环组成

  • 外层:寻找未被标记的元素(素数)
  • 内层:把素数的倍数标记为合数(composite)

 

java代码(找出自然数upperBound内,包括upperBound的所有的素数,并且把它们输出)

 1  public void runEratosthenesSieve(int upperBound) {
 2       int upperBoundSquareRoot = (int) Math.sqrt(upperBound);
 3     /*这里取平方是因为通过数学推理可以知道只需要判断到upperBound的上界即可。
 4       第一次写的读者可以把循环的次数设置成upperBound,便于理解*/
 5       boolean[] isComposite = new boolean[upperBound + 1];
 6    //这个boolean类型的数组是为了标记upperBound以内的自然数
 7 
 8       for (int m = 2; m <= upperBoundSquareRoot; m++) {
 9             if (!isComposite[m]) {
10                   System.out.print(m + " ");
11                   for (int k = 2 * m; k <= upperBound; k += m)
                         12 isComposite[k] = true; 13 } 14 } 15 for (int m = upperBoundSquareRoot; m <= upperBound; m++) 16 if (!isComposite[m]) 17 System.out.print(m + " "); 18 }

 

 

 

 

题意:输出第M~N个素数。

思路:利用筛法把素数表打印至第N个素数,然后按格式输出。

 

java代码

 1 class Prime1{
 2     private int maxn =100010;
 3     private int a[] =new int[maxn];
 4 
 5     void isPrime(int n){
 6         boolean flag[] = new boolean[maxn];
 7         int index=0;
 8         for(int i=2;i<maxn;i++){
 9             if(index>=n) break;//无需找出第n个素数后的素数
10             if(! flag[i]){
11             a[index]=i;
12             index++;
13                 for (int j=2*i;j<maxn;j+=i){
14                     flag[j]=true;
15                 }
16             }
17         }
18     }
19 
20     void outprint(int m,int n){
21         int count=0;
22         isPrime(n);
23         for(int i=m-1;i<n;i++){
24             if(count%10!=0&&i!=n-1){
25                 System.out.print(a[i]+" ");
26             }else{
27                 System.out.println();
28             }
29         }
30     }
31 }

 

改进筛法:

*我们注意到,算法中标记倍数可以从已找到的素数的平方开始标记(而不是从它的两倍开始)

 

对于 m = 2,原先的算法标记了

  2*2  3*2  4*2  5*2  6*2  7*2  8*2  ...

对于 m = 3,原先的算法标记了

  2*3  

2*3这一步在m = 2的时候已经被标记

对于 m = 5,

  2*5  3*5  4*5(= 10*2)

已经在m = 2以及m = 3的时候被标记了

 

这里缺少了严格的数学证明,有兴趣的读者朋友可以自己证明。 

 

对范围在2~100的数应用改进后埃式筛法筛选出这里面的所有素数的过程:

 

装有2~100自然数的数组的最初状态。

 

 

   

2是素数,标记所有2的倍数。从4开始。

 

3在上一步没有被标记,所以3是素数。标记所有3的倍数,从9开始。

 

5是素数,标记所有5的倍数,从25开始

 

7是素数,标记所有7的倍数,从49开始

 

11的平方,超过了100,在数组里面所有没有被标记的数字都是素数 

 

最终得到的结果

 

java代码(找出自然数upperBound内,包括upperBound的所有的素数,并且把它们输出)

 1  public void runEratosthenesSieve(int upperBound) {
 2       int upperBoundSquareRoot = (int) Math.sqrt(upperBound);
 3     /*这里取平方是因为通过数学推理可以知道只需要判断到upperBound的上界即可。
 4       第一次写的读者可以把循环的次数设置成upperBound,便于理解*/
 5       boolean[] isComposite = new boolean[upperBound + 1];
 6    //这个boolean类型的数组是为了标记upperBound以内的自然数
 7 
 8       for (int m = 2; m <= upperBoundSquareRoot; m++) {
 9             if (!isComposite[m]) {
10                   System.out.print(m + " ");
11                   for (int k = m * m; k <= upperBound; k += m)
                         12 isComposite[k] = true; 13 } 14 } 15 for (int m = upperBoundSquareRoot; m <= upperBound; m++) 16 if (!isComposite[m]) 17 System.out.print(m + " "); 18 }

参考文献:

1.Peter J. Giblin. Primes and Programming.

2.Hans Riesel. Prime Numbers and Computer Methods for Factorization.

 

 

 

 

 

 

              

    

posted @ 2018-05-11 17:00  HelloTum  阅读(210)  评论(0编辑  收藏  举报