algorithm - 是否有快速、实用的素数生成器?

标签 algorithm functional-programming primes sieve-of-eratosthenes

假设我有一个自然数 n,并且我想要一个包含 n 以内的所有素数的列表(或其他任何内容)。

经典的素数筛算法在 O(n log n) 时间和 O(n) 空间内运行——它适用于更多命令式语言,但需要 in-以基本的方式对列表和随机访问进行修改。

有一个涉及优先级队列的功能版本,非常漂亮——你可以看看here .这在大约 O(n/log(n)) 时具有更好的空间复杂度(渐近更好,但在实际规模上值得商榷)。不幸的是,时间分析很糟糕,但它非常接近 O(n^2)(实际上,我认为它大约是 O(n log(n) Li(n)) ,但是 log(n) Li(n) 大约是 n)。

从渐近的角度来说,使用连续的试验除法在生成每个数字时检查其素数实际上会更好,因为这只需要 O(1) 空间和 O (n^{3/2}) 次。有没有更好的办法?

编辑:事实证明我的计算完全不正确。文章中的算法是O(n (log n) (log log n)),文章对此进行了解释和证明(见下面的答案),而不是我上面放的复杂的乱七八糟的。如果有一个真正的 O(n log log n) 纯算法,我仍然很乐意看到。

最佳答案

这是 Melissa O'Neill 算法的 Haskell 实现(来自链接文章)。与 Gassa 链接到的实现不同,我尽可能少地使用惰性,因此性能分析很清楚——O(n log n log log n),即 n log log 中的线性对数n,命令式埃拉托色尼筛法进行的写入次数。

堆实现只是一个锦标赛树。平衡逻辑在push;通过每次交换子树,我们确保对于每个分支,左子树的大小与右子树的大小相同或大一倍,从而确保深度为 O(log n)。

module Sieve where

type Nat = Int

data Heap = Leaf !Nat !Nat
          | Branch !Nat !Heap !Heap
          deriving Show

top :: Heap -> Nat
top (Leaf n _) = n
top (Branch n _ _) = n

leaf :: Nat -> Heap
leaf p = Leaf (3 * p) p

branch :: Heap -> Heap -> Heap
branch h1 h2 = Branch (min (top h1) (top h2)) h1 h2

pop :: Heap -> Heap
pop (Leaf n p) = Leaf (n + 2 * p) p
pop (Branch _ h1 h2)
  = case compare (top h1) (top h2) of
        LT -> branch (pop h1) h2
        EQ -> branch (pop h1) (pop h2)
        GT -> branch h1 (pop h2)

push :: Nat -> Heap -> Heap
push p h@(Leaf _ _) = branch (leaf p) h
push p (Branch _ h1 h2) = branch (push p h2) h1

primes :: [Nat]
primes
  = let helper n h
          = case compare n (top h) of
                LT -> n : helper (n + 2) (push n h)
                EQ -> helper (n + 2) (pop h)
                GT -> helper n (pop h)
      in 2 : 3 : helper 5 (leaf 3)

关于algorithm - 是否有快速、实用的素数生成器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42118496/

相关文章:

查找多边形最小边数的算法

algorithm - 次二次和二次算法之间的区别

functional-programming - 有人使用 SML 或 OCaml 来构建真实世界的 GUI 吗?

algorithm - 在给定所有先验条件的情况下找到下一个素数

c++ - 找到数字的主要因素的更好方法

java - 将 byte[] 转换为 short[],使得每个 short 元素包含 13 位数据

java - 使用 Java 比较目录 : how could I recognize deleted files?

recursion - 有没有更有效的方法来编写这个递归过程?

Java 函数式编程 : creating a map of functions

c - 在 C 中扫描二维数组中的素数