List 埃拉托斯烯Haskell筛及复合材料列表
我必须为一个项目在Haskell中实现Eratosthenes筛的经典问题。我不需要计算每个素数,只需要比较列表中的数字。例如,我传递了一个潜在素数列表(参数1)和一个组合列表(列表2)<代码>筛选[2..10][]结果与列表List 埃拉托斯烯Haskell筛及复合材料列表,list,haskell,primes,sieve-of-eratosthenes,List,Haskell,Primes,Sieve Of Eratosthenes,我必须为一个项目在Haskell中实现Eratosthenes筛的经典问题。我不需要计算每个素数,只需要比较列表中的数字。例如,我传递了一个潜在素数列表(参数1)和一个组合列表(列表2)筛选[2..10][]结果与列表[2,3,5,7] 我认为我非常接近,它可以编译,但它会将每一项附加到主列表中,而不是扔掉组合。我的想法是,它需要所有数字的列表x2..10或任何东西,复合列表y使用elem来查看列表x的头是否在列表y中,如果是,则附加到列表z并打印。提前谢谢 目前,我的代码返回第一个列表中的所有
[2,3,5,7]
我认为我非常接近,它可以编译,但它会将每一项附加到主列表中,而不是扔掉组合。我的想法是,它需要所有数字的列表x2..10
或任何东西,复合列表y使用elem
来查看列表x的头是否在列表y中,如果是,则附加到列表z并打印。提前谢谢
目前,我的代码返回第一个列表中的所有内容,并拒绝排序<代码>筛选[2..10][]结果为[2,3,4,5,6,7,8,9,10]
sieve ::[Int]->[Int]->[Int]
z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) ys)
else ((head xs):z)
您显示的程序没有多大意义,首先将始终使用
sieve x[]
,此外,您应该检查一个元素是否可被另一个列表整除。最后,您应该使调用递归,因为z
被定义为空列表,所以不能使用headxs:z
执行此操作
让我们从基本情况开始:如果左侧列表为空,则不管第二个列表的内容如何,都会返回空列表。由于筛选不产生任何结果:
sieve [] _ = []
下一步,我们寻找感应情况,使用as模式:
sieve (x:xs) ds = ...
现在我们需要枚举已经找到的元素列表。从找到的元素中的任何一个可以除x的那一刻起,我们就知道这个数字不是(相对)素数。该条件形式化为:
(==) 0 . mod x :: Integral b => b -> Bool
或在ds
列表上迭代:
any ((==) 0 . mod x) ds
如果存在这样的元素,我们只需跳过该元素,并使用sieve xs ds
调用归纳案例
如果没有这样的元素,我们将其添加到ds
列表中并发出它。结果是:x:sievexs(x:ds)
。因此,归纳情况是:
sieve (x:xs) ds | any ((==) 0 . mod x) ds = sieve xs ds
| otherwise = x : sieve xs (x:ds)
我们可以通过为sieve xs
创建一个特定变量来缩短这个时间:
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
因此,其全部功能是:
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) ds = rec ds
| otherwise = x : rec (x:ds)
where rec = sieve xs
您可以通过两种方式提高性能:
- 在
末尾添加ds
。这确实是一项更昂贵的行动。但过了一段时间,你就不会经常添加数字了。这很有趣,因为在这种情况下,x
看起来像ys
,而不是[2,3,5,7,11]
。现在一个数字被[11,7,5,3,2]
(50%)整除的几率大于一个数字被2
(9.9%)整除的几率。最好先尝试最有可能成功的测试11
- 此外,您可以在除数达到待测数字的平方根后结束检查:如果一个数字不能被小于该数字的数字整除,那么它肯定不能被大于平方根的数字整除
sieve [] _ = []
sieve (x:xs) ds | any ((==) 0 . mod x) $ takeWhile (\y -> y*y <= x) ds = rec ds
| otherwise = x : rec (ds++[x])
where rec = sieve xs
sieve[].[]
sieve(x:xs)ds | any(==)0.mod x)$takeWhile(\y->y*y你称之为sieve
通常被称为减,从第一个列表中减去第二个列表,假设这两个列表都是有序的,增加数字列表。然后只比较两个head元素就足够了,没有任何elem
调用
但如果您为z
提供了一个正确的定义,它仍然可以工作z=[]
只是一个占位符,以使其可编译(对吗?);它不是正确的定义。它应该是:
sieve :: [Int] -> [Int] -> [Int]
-- z = []
sieve [] [] = []
sieve x [] = x
sieve [] y = y
sieve xs ys = if ((elem (head xs)) ys) then (sieve (tail xs) z)
else ((head xs) : sieve (tail xs) ys )
where
z = ... -- need to remove (head xs) from ys
对于最后一条评论的任务,您可以使用例如function
如果没有复合列表,这仍然无法生成素数列表,因此初始调用不能在第二个列表为空的情况下进行(否则,由于sieve x[]=x
等式,您将得到与您相同的第一个参数):
但是什么是复合材料呢?埃拉托什内斯的答案是,为什么,它们是素数的倍数!(试算法说:复合材料有其他素数作为其除数)
给定一个素数,比如说2,我们只是数数:2,4,6,…;对于3,比如说,它是3,6,9,12,…;求它的倍数。我们把它写下来:
composites = mutliplesOf primes
mutliplesOf primes = [ mult | p <- primes, mult <- [...] ]
我们似乎在追逐自己的尾巴;我们还没有素数
;我们可以用什么来代替呢?找到非素数和素数的倍数有什么害处吗
在你有了一个运行的代码之后,试着找到一种使用素数的方法。你对sieve[2..10][
模式的调用与定义sieve x[]相匹配=x
,因此没有使用sieve
的其他子句。您显示的程序没有多大意义,首先是sieve x[]
将始终被使用,此外,在中,你应该检查一个元素是否可以被另一个列表整除。最后,你应该使调用递归,这是你不能用头xs:z
做的,因为z
被定义为空列表。不能在Eratosthenes的筛子中执行整除性检查!!@WillNess:then(a)为什么使用可分性检查,(b)如果在大多数应用程序中将元素添加到ys
,元素将更小,因此筛子将允许所有元素;以及(3)这篇维基文章明确指出。你确实可以实现一个版本,其中复合物是为ys
计算的,但这会降低算法的性能。@CommuSoft(a)不是一个埃拉托什尼的筛子,而是一个试用除法的筛子。(b)不理解你,抱歉。(c)是的,它说“它经常与埃拉托斯烯筛相混淆”也就是说,它不是埃拉托斯烯筛,而是因为它而混淆。如果你还没有看到,也许它会是一本有趣的读物。:)非常好的解释-但我认为结果的顺序是错误的(这可能是一个问题,也可能不是一个问题)
composites = mutliplesOf primes
mutliplesOf primes = [ mult | p <- primes, mult <- [...] ]
primes = primesAmong input
primesAmong input = sieve input (mutliplesOf primes)