【问题标题】:What Time Complexity Does Haskell's "tail"-Function Have?Haskell 的“尾巴”函数的时间复杂度是多少?
【发布时间】:2017-07-12 05:12:11
【问题描述】:

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

我猜想对于大小为 n 的列表,tail 函数将是 O(n),即只是将尾部复制到一个新列表并返回该列表。但是话又说回来,我对 Haskell 的底层架构了解不多(我是该语言的新手)。

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

提前致谢:)

【问题讨论】:

    标签: haskell


    【解决方案1】:

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

    挑战问题:为什么init(保留列表的最后一个元素除外)运行时间为 O(n)?为什么上面的共享论点在那里不适用?

    【讨论】:

    • 至于挑战题;如果我可以假设该列表是一个单链表(如 Williems 回答中所述),它应该是 O(n) 因为如果不删除指向最后一个元素(不可能)或将值复制到不包含最后一个元素的新链表中。这是正确的推理方式吗?
    • @SimonSirak 但考虑data NList a = NList ([a], Int) 其中Int 是列表的长度。 init 然后简单地变成second (subtract 1),或多或少。
    【解决方案2】:

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

    Haskell 中的列表是一个链表。定义为:

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

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

    basetail的源码定义为:

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

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

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

    【讨论】:

    • 我不知道它实际上是一个链表!感谢您提供非常有用的信息 :) 接受的答案与此相结合是一个有益健康的答案!
    猜你喜欢
    • 1970-01-01
    • 2020-12-03
    • 2017-09-11
    • 2020-03-13
    • 1970-01-01
    • 2016-05-21
    • 2018-11-02
    相关资源
    最近更新 更多