【问题标题】:In Sieve of Eratosthenes implementation with Haskell, why are the multiples of 3,5,7.. not removed from the list?在使用 Haskell 实现 Eratosthenes 筛法中,为什么 3,5,7.. 的倍数没有从列表中删除?
【发布时间】:2018-07-29 18:48:03
【问题描述】:

我目前正在自学 Doets 和 Eijck 所著的《Haskell Road to Logic, Maths and Programming 一书,我正在阅读第 3 章。

在本章中,作者提供了实现埃拉托色尼筛法算法的Haskell代码,我不喜欢他们的实现,所以我尝试给出自己的实现;但是,我的代码版本确实只删除了 2 的倍数,我无法找出原因。代码如下:

sieve :: [Int] -> [Int]
sieve (0:xs) = sieve xs
sieve (x:xs) = x : sieve (mark x 2 xs)
 where
 mark :: Int -> Int -> [Int] -> [Int]
 mark n k (y:ys)
  | y == n*k = 0 : (mark n (k+1) ys)
  | otherwise = y : (mark n (k) ys) 

输出是

*Ch3> sieve [2..]
[2,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,...

那么,为什么代码没有对其他数字的倍数进行相同的删除操作,例如 3,5,7.. ?

【问题讨论】:

标签: haskell primes sieve-of-eratosthenes


【解决方案1】:

简答:mark 中的计数器 k 不会为 n > 2 增加。

mark x 2 [2..] 正确地从列表中删除了偶数,因此下一步是调用sieve [3,5..],相当于3:sieve (mark 3 2 [5,7..]),让我们看看这里发生了什么。

mark 3 2 [5,7..](可能)尝试从列表中删除所有3 的倍数,但它会逐步执行此操作,首先尝试从列表中删除 6。但是,由于列表仅包含奇数,因此永远不会从列表中删除 6,并且第一种情况总是失败。代码继续检查 6,从不向上移动到删除 9。

同样,25 永远不会被删除,因为代码只会尝试从列表中删除 2*5

【讨论】:

  • 感谢您的回答。我现在已经更改了代码的实现,它现在可以工作了。
猜你喜欢
  • 1970-01-01
  • 2018-02-11
  • 2019-07-03
  • 1970-01-01
  • 2011-09-26
  • 2021-12-19
  • 1970-01-01
  • 1970-01-01
  • 2019-04-14
相关资源
最近更新 更多