【问题标题】:Segmented Sieve of Eratosthenes - JavaEratosthenes 的分段筛 - Java
【发布时间】:2019-01-06 21:54:58
【问题描述】:

所以我试图在 Java 中实现 Eratosthenes 的分段筛,这是我能做的最好的。当我运行它时,它没有给出任何错误,但它没有返回任何内容,尽管我在最后添加了“System.out.println”以打印出所有剩余的素数。提前感谢您的建议

public class SegmentedSieveofEratosthenes  {

public static void main(String[] args) throws java.lang.Exception {
    Scanner in = new Scanner(System.in);

    int n = in.nextInt();
    int m = in.nextInt();
    boolean[] v = new boolean[1000000];
    int[] primes = new int[1000000];
    //counter for the primes vector
    int counter = 0;

    for(int i=2;i<=(int)Math.sqrt(m);i++)
    {
        v[i]=true;
    }

    for(int i=2;i<=(int)Math.sqrt(m);i++)
    {
        if(v[i]=true)
        {
            primes[counter]=i;
            counter=counter+1;
            for(int j=i+1;j<=(int)Math.sqrt(m);j++)
            {
                if(j%i==0)
                {
                    v[j]=false;
                }
            }
        }
    }

    boolean[] flags = new boolean[1000000];
    for(int i=n;i<=m;i++)
    {
        flags[i]=true;
    }

    for(int i=0;i<counter;i++)
    {
        int start = (n/primes[i])*3;
        for(int j=start+i;j<=m;j=j+i)
            flags[j]=false;
    }

    for(int i=n;i<=m;i++)
        if(flags[i]==true)
            System.out.println(i);

    in.close();
    }
  }

【问题讨论】:

  • 只是评论:选择花括号样式。同一行 curly 和 next line curly 的社区不相处。这种同时使用两者的方式会引发一场你从未见过的战争。
  • @PaulNikonowicz 哦,好的,谢谢!

标签: java algorithm


【解决方案1】:

您的实施存在三个明显的问题。第一个问题是您在某个条件下将 v[i] 分配为 true

if(v[i]=true)

然后在for循环的终止条件中出现了一些错误,特别是

for (...; i<=m; ...)

而不是

for (...; i<m; ...)

最后,你的数学有问题

int start = (n/primes[i])*3;
for(int j=start+i;j<=m;j=j+i)
    flags[j]=false;

我确定这是一个小修复,但我无法弄清楚,所以我只写了自己的

int start = n + (-n % primes[i]);
for(int j=start;j<m;j+=primes[i])
    flags[j]=false;

此外,我对您的筛子做了一些小改动以加快速度。我没有检查以素数为模数表示素数后的每个数字,而是从prime^2(其中^ 表示求幂)开始并以prime 递增,只标记没有浪费检查的倍数。

原创

primes[counter]=i;
counter=counter+1;
for(int j=i+1;j<=(int)Math.sqrt(m);j++)
{
    if(j%i==0)
    {
        v[j]=false;
    }
}

优化

primes[counter++]=i;
for(int j=i*i;j<=(int)Math.sqrt(m);j+=i)
{
    v[j]=false;
}

放在一起-

import java.util.Scanner;
import java.util.Arrays;
public class SegmentedSieveofEratosthenes  {

    public static void main(String[] args) throws java.lang.Exception {
        Scanner in = new Scanner(System.in);

        int n = in.nextInt();
        int m = in.nextInt();
        boolean[] v = new boolean[1000000];
        int[] primes = new int[1000000];
        //counter for the primes vector
        int counter = 0;

        for(int i=2;i<=(int)Math.sqrt(m);i++)
        {
            v[i]=true;
        }

        for(int i=2;i<=(int)Math.sqrt(m);i++)
        {
            if(v[i])
            {
                primes[counter++]=i;
                for(int j=i*i;j<=(int)Math.sqrt(m);j+=i)
                {
                    v[j]=false;
                }
            }
        }

        boolean[] flags = new boolean[1000000];
        for(int i=n;i<m;i++)
        {
            flags[i]=true;
        }

        for(int i=0;i<counter;i++)
        {
            int start = n + (-n % primes[i]);
            for(int j=start;j<m;j+=primes[i])
                if (j != primes[i])
                    flags[j]=false;
        }

        for(int i=n;i<m;i++)
            if(flags[i])
                System.out.println(i);

        in.close();
    }
}

例如 n = 800m == 1000 的输出

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

【讨论】:

  • 你好,迪利安!非常感谢你的回复。我在我的代码中实现了它,现在效果很好!但是,在我输入的两个数字范围之间,它不包括“m”或最后一个。这就是为什么我一直添加 for (...; I
  • 我会推荐int m = in.nextInt() + 1;,其中将包括m
  • @TheSilentCoder。另外,我想提一下(但没有放在帖子中,因为您没有提到性能),可以通过将所有出现的 (int)Math.sqrt(m) 替换为您在开始时计算一次的变量来更快地优化。此外,如果您在素数 2 中硬编码,所有其他的都是奇数,因此您可以增加 2 而不是 1。
  • 另外,如果这回答了您的问题,请随时接受,以便其他人可以看到问题已解决。
  • @Dillion Davis,非常感谢您的帮助,我检查了您的答案!但是,用 2 和 10 试试你的解决方案,我相信它不起作用。有什么办法可以改变吗?这是我现在的代码:[link](codeshare.io/alx4em) 再次感谢!
【解决方案2】:

您在以下行中没有结束循环:

for(int j=start+i;j<=m;j=j+i)

因为变量ijstart总是等于0。

学会调试你的程序,对你有很大帮助;)

附言保持代码干净,在表达式中使用空格,例如 i = n; i 而不是 i=n;i

【讨论】:

  • 除了那一行之外还有更多问题 - 请参阅我的答案。但我确实想说我完全同意你关于格式的说明。在我的回答中,我保留了 OP 的格式以保持一致性,但在实践中,我永远不会在代码高尔夫之外写出这样的条件。
猜你喜欢
  • 2016-04-06
  • 2014-07-20
  • 2022-11-28
  • 2015-09-06
  • 2017-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-05
相关资源
最近更新 更多