繁体   English   中英

算法:使用Eratosthenes筛选列出所有素数

[英]Algorithm: List all prime number using Sieve of Eratosthenes

我已经实现Sieve of Eratosthenes用于查找从1到n的素数列表。 我的代码适用于从1到10,000的输入,但我得到以下值> 100,000:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -2146737495
        at SieveOfEratosthenes.main(SieveOfEratosthenes.java:53)

我能够找到问题,当我正在进行i * i时它处于for循环中,因为它已经超出Integer范围( Integer.MAX_VALUE ),但我找不到解决方案。 有人可以建议我可以做些什么改变我也很感激有人建议我在这个实现中提高效率吗?

public class SieveOfEratosthenes {

    public static void main(String[] args) {

        Integer num = Integer.parseInt(args[0]);
        Node[] nodes = new Node[num + 1];

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

            Node n = new Node();
            n.setValue(i);
            n.setMarker(true);

            nodes[i] = n;
        }

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

            if(nodes[i].getMarker() && nodes[i].getValue() > 1) {
                System.out.println("Prime " + nodes[i].getValue());
            } else {
                continue;
            }

            for(int j = i * i; j < nodes.length
                                    && nodes[i].getMarker(); j = j + i) {
                nodes[j].setMarker(false);
            }
        }

        System.out.println(l.size());

    }
}

class Node {

    private int value;
    private boolean marker;

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }

    public void setMarker(boolean marker) {
        this.marker = marker;
    }

    public boolean getMarker() {
        return this.marker;
    }

    public String toString() {
        return ("Value : " + marker + " value " + value);
    }
}

从本质上讲, for(int j = i * i; ...循环是为了越过i所有倍数。只有从i * i开始交叉才有意义,因为所有较小的倍数已经被较小的除数划掉了。

至少有两种方法可以从这里开始。

首先,你可以从i * 2而不是i * i 这将摆脱溢出。 从糟糕的一面来看,筛子的复杂性将从O(n log log n)增长到O(n log n)。

其次,您可以检查i * i是否已经过多,如果是,则完全跳过循环。 回想一下,如果没有溢出发生,那么它本质上是跳过的,因为i大于nodes.length平方根。 例如,只需在循环之前添加if (i * 1L * i < nodes.length)

    for(int i = 1; i < nodes.length; i++) {
        if(nodes[i].getMarker() && nodes[i].getValue() > 1) {
            System.out.println("Prime " + nodes[i].getValue());
        } else {
            continue;
        }

int limit = 2 << 14;
for(int i = 1; i < nodes.length; i++) {
    if(nodes[i].getMarker() && nodes[i].getValue() > 1 && i <= 2 << 15) {
        System.out.println("Prime " + nodes[i].getValue());
        if (i > limit) {
            continue;
        }
    } else {
        continue;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM