当我想到自己时,我正在阅读关于Haskell的教程; Haskell tail
函数的时间复杂度(以及为什么)?(我在任何文档中找不到答案)
我猜想对于大小为n的列表,tail
函数将是 O(n),即只是将尾部复制到新列表并返回该列表。但话说回来,我对Haskell的基础架构知之甚少(我不熟悉该语言)。
当然,我可以计时。但我还不知道如何在Haskell中计算时间,我也想了解Haskell如何处理问题,证明为什么它是O(n)/ O(1)或其他什么。
提前致谢:)
答案 0 :(得分:14)
Haskell语言没有指定。但在GHC(最常用的实现)中,它是O(1)。尾部不需要复制 - 在原始列表和只使用列表尾部的人之间共享是安全的 - 因为Haskell中的所有内容都是不可变的。
挑战问题:为什么init
除了列表的 last 元素外,其余都在O(n)中运行?为什么上面的共享参数不适用于那里?
答案 1 :(得分:6)
简短回答:如果列表已构建到该节点, O(1) 。
Haskell中的列表是链接列表。它被定义为:
data [a] = [] | a : [a]
这意味着要么我们有空列表,要么有a : [a]
构造。所以带有head
(a
)的节点引用类型a
的对象,引用列表的tail
[a]
(可以是空列表或其他节点)。
base
中tail
的源代码定义为:
tail :: [a] -> [a] tail (_:xs) = xs tail [] = errorEmptyList "tail"
它在O(1)中运行,因为我们只需按照指向该节点“尾部”的指针。
请注意 Haskell懒惰地工作。这不是因为我们得到了[a]
类型的对象,我们有一个具体化列表:通常Haskell首先必须评估它已经给出的表达式树到给定节点。这可能导致评估复杂且耗时的算法。所以它取决于你给出的表达式树。