代码之家  ›  专栏  ›  技术社区  ›  Cade Bryant

Eratosthenes筛:加快“交叉倍数”步骤

  •  1
  • Cade Bryant  · 技术社区  · 2 年前

    我使用埃拉托斯梯尼筛算法实现了一个列出素数的函数,如下所示:

    func ListPrimes(n int) []int {
        primeList := make([]int, 0)
        primeBooleans := SieveOfEratosthenes(n)
        for p := 0; p < n+1; p++ {
            if primeBooleans[p] == true {
                primeList = append(primeList, p)
            }
        }
        return primeList
    }
    
    func SieveOfEratosthenes(n int) []bool {
        primeBooleans := make([]bool, n+1)
        sqrtN := math.Sqrt(float64(n))
        for k := 2; k <= n; k++ {
            primeBooleans[k] = true
        }
        for p := 2; float64(p) <= sqrtN; p++ {
            if primeBooleans[p] == true {
                primeBooleans = CrossOffMultiples(primeBooleans, p)
            }
        }
        return primeBooleans
    }
    
    func CrossOffMultiples(primeBooleans []bool, p int) []bool {
        n := len(primeBooleans) - 1
        for k := 2 * p; k <= n; k += p {
            primeBooleans[k] = false
        }
        return primeBooleans
    }
    

    但我发现了一个效率低下的问题:即 CrossOffMultiples 被呼叫的次数超过了必要的次数。IOW,由于任何倍数 m 会有多个因素将其分开。但我似乎不知道如何利用这一点信息,从而减少次数 CrossOffMultiples 被调用。我相信有办法做到这一点,但由于某种原因,它避开了我。

    有什么建议吗?

    1 回复  |  直到 2 年前
        1
  •  2
  •   Kelly Bundy    2 年前

    如果你减少次数 CrossOffMultiples 被称为,也就是说,你不把它称为素数 p 然后 p * p 不会被忽略。但你能做的是在 p*p 而不是 2 * p

    多次划掉数字是正常的,埃拉托斯梯尼的筛子就是这样做的。 Linear Sieve 是您可能感兴趣的类似算法。

    推荐文章