简体   繁体   English

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

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

I have implemented Sieve of Eratosthenes for finding the list of prime number from 1 to n. 我已经实现Sieve of Eratosthenes用于查找从1到n的素数列表。 My code is working fine for inputs from 1 to 10,000 but I am getting following for values >100,000: 我的代码适用于从1到10,000的输入,但我得到以下值> 100,000:

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

I am able to find the issue, which is in the for loop when I am doing i * i as it is going out of Integer range ( Integer.MAX_VALUE ), but I could not find the solution. 我能够找到问题,当我正在进行i * i时它处于for循环中,因为它已经超出Integer范围( Integer.MAX_VALUE ),但我找不到解决方案。 Can someone suggest me what changes can be done also I appreciate if someone suggest me any improvement for efficiency in this implementation? 有人可以建议我可以做些什么改变我也很感激有人建议我在这个实现中提高效率吗?

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

Essentially, the for(int j = i * i; ... loop is to cross out all multiples of i . It makes sense only to cross out starting from i * i , since all lesser multiples are already crossed out by their lesser divisors. 从本质上讲, for(int j = i * i; ...循环是为了越过i所有倍数。只有从i * i开始交叉才有意义,因为所有较小的倍数已经被较小的除数划掉了。

There are at least two ways to go from here. 至少有两种方法可以从这里开始。

First, you can start crossing out from i * 2 instead of i * i . 首先,你可以从i * 2而不是i * i This will get rid of the overflow. 这将摆脱溢出。 On the bad side, the complexity of the sieve would grow from O(n log log n) to O(n log n) then. 从糟糕的一面来看,筛子的复杂性将从O(n log log n)增长到O(n log n)。

Second, you can check whether i * i is already too much, and if it is, skip the loop completely. 其次,您可以检查i * i是否已经过多,如果是,则完全跳过循环。 Recall that it is essentially skipped anyway for i greater than the square root of nodes.length if no overflow occurs. 回想一下,如果没有溢出发生,那么它本质上是跳过的,因为i大于nodes.length平方根。 For example, just add an if (i * 1L * i < nodes.length) before the loop. 例如,只需在循环之前添加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;
        }

TO

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