Haskell" tail" -Function有什么时间复杂性?

时间:2017-07-11 20:49:39

标签: haskell

当我想到自己时,我正在阅读关于Haskell的教程; Haskell tail函数的时间复杂度(以及为什么)?(我在任何文档中找不到答案)

我猜想对于大小为n的列表,tail函数将是 O(n),即只是将尾部复制到新列表并返回该列表。但话说回来,我对Haskell的基础架构知之甚少(我不熟悉该语言)。

当然,我可以计时。但我还不知道如何在Haskell中计算时间,我也想了解Haskell如何处理问题,证明为什么它是O(n)/ O(1)或其他什么。

提前致谢:)

2 个答案:

答案 0 :(得分:14)

Haskell语言没有指定。但在GHC(最常用的实现)中,它是O(1)。尾部不需要复制 - 在原始列表和只使用列表尾部的人之间共享是安全的 - 因为Haskell中的所有内容都是不可变的。

挑战问题:为什么init除了列表的 last 元素外,其余都在O(n)中运行?为什么上面的共享参数不适用于那里?

答案 1 :(得分:6)

简短回答:如果列表已构建到该节点, O(1)

Haskell中的列表是链接列表。它被定义为:

data [a] = [] | a : [a]

这意味着要么我们有空列表,要么有a : [a]构造。所以带有heada)的节点引用类型a的对象,引用列表的tail [a](可以是空列表或其他节点)。

basetail的源代码定义为:

tail                    :: [a] -> [a]
tail (_:xs)             =  xs
tail []                 =  errorEmptyList "tail"

它在O(1)中运行,因为我们只需按照指向该节点“尾部”的指针。

请注意 Haskell懒惰地工作。这不是因为我们得到了[a]类型的对象,我们有一个具体化列表:通常Haskell首先必须评估它已经给出的表达式树到给定节点。这可能导致评估复杂且耗时的算法。所以它取决于你给出的表达式树