Java I';我试图实现埃拉托斯坦筛,但它只适用于小于33的数字

Java I';我试图实现埃拉托斯坦筛,但它只适用于小于33的数字,java,sieve-of-eratosthenes,Java,Sieve Of Eratosthenes,我正试图为Eratosthenes筛编写一个程序,它可以工作,但如果输入数为33或更大,我会出现以下错误: Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0 at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64) at java.b

我正试图为Eratosthenes筛编写一个程序,它可以工作,但如果输入数为33或更大,我会出现以下错误:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
    at java.base/java.util.Objects.checkIndex(Objects.java:373)
    at java.base/java.util.ArrayList.get(ArrayList.java:425)
    at Main.main(Main.java:23)
这是我使用的代码

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner read = new Scanner(System.in);
        int nr = read.nextInt();

        ArrayList<Integer> listA = new ArrayList<Integer>();
        ArrayList<Integer> listB = new ArrayList<Integer>();

        for (int i = 2; i <= nr; i++)
                listA.add(i);
        //System.out.println(listA);
        int m = 2;
        listB.add(m);
        while (m <= nr-2) {
            listA.removeAll(Arrays.asList(m));
            for (int j = m*2; j <= nr; j = j + m) {
                listA.removeAll(Arrays.asList(j));
            }
            m = listA.get(0);
            listB.add(m);
        }
        System.out.println(listB);

    }
}
import java.util.ArrayList;
导入java.util.array;
导入java.util.Scanner;
公共班机{
公共静态void main(字符串[]args){
扫描仪读取=新扫描仪(System.in);
int nr=read.nextInt();
ArrayList listA=新的ArrayList();
ArrayList listB=新的ArrayList();

对于(int i=2;i当您获得
java.lang.IndexOutOfBoundsException
时,这意味着此时您已经从
listA
中删除了所有数字,因此您无法执行
listA.get(0)

我会声明一个布尔数组,并将它们全部设置为true。你可以假装这些是0-n之间的数字

然后,通过从2开始将每个非素数设置为false,并将乘法设置为false等。在乘法之前,您可以检查该数字是否已设置为false,这意味着不需要将该数字相乘,因为所有乘法都已设置为false。这使算法大大加快

最后打印出从2开始的所有素数

您可以删除
数组。填充
以提高效率,但随后需要反转所有其他逻辑,因为boolean将默认为false

        boolean[] primeNumbers = new boolean[nr + 1];
        Arrays.fill(primeNumbers, true);

        int m = 2;
        while (m <= Math.sqrt(nr)) {
            if (primeNumbers[m])
                for (int j = m * 2; j <= nr; j = j + m) {
                    primeNumbers[j] = false;
                }
            m++;
        }

        for (int i = 2; i <= nr; i++) {
            if (primeNumbers[i]) System.out.println(i);
        }
boolean[]素数=新布尔[nr+1];
数组。填充(素数,真);
int m=2;

而(m)则不需要
listA.removeAll(Arrays.asList(m));
,因为您只删除一个值。您可以直接执行
listA.remove(m)
。至于您的其余代码,我不确定您想要完成什么。您可以使用for循环和布尔[]您不需要两个数组列表请指示代码的哪一行抛出异常顺便说一句,最简单和最快的实现是一个巨大的
boolean[]
,但是如果您的筛子很大(百万),请使用
BitSet
,它每个值仅使用1位。请注意,实际限制是
根nr
(而不是
nr/2
),因为这允许您跳过检查逆序因子(即,2*17->17*2)。还要注意的是,第二个好的优化(在速度和内存方面)是简单地排除所有偶数,因为所有偶数都是非素数(当然,除2外)-数组大小可以是一半。