【问题标题】:What is the most efficient purely functional algorithm for generating all prefixes of a list?生成列表的所有前缀的最有效的纯函数算法是什么?
【发布时间】:2010-11-27 06:03:45
【问题描述】:
prefixes ls = zipWith take [1 .. length ls] (repeat ls)

有没有比这更好的方法?直观地说,在我看来,在纯函数式语言中无法获得低于 O(n²) 的算法,因为必须应用反向或追加 n 次。不过,我不知道如何证明这一点。

【问题讨论】:

    标签: algorithm haskell functional-programming performance


    【解决方案1】:

    我认为你是对的。不能共享列表的脊椎,因为所有尾部都不同。因此,如果完全评估前缀列表,将占用完整的 Θ(n2) 空间,这必须花费 Ω(n2) 时间来生成。

    请注意,您编写的函数(较懒的版本)在Data.List 中作为inits 可用。

    你可以做一个巧妙的优化。这个等式成立:

    map (foldl f z) . inits = scanl f z
    

    scanl 以线性时间运行。因此,如果您可以将要对每个前缀执行的操作表述为左折叠,那么您可以避免构建前缀列表的二次复杂度。

    【讨论】:

      【解决方案2】:

      这不是依赖于表示吗?如果您将列表表示为连续存储加上开始和结束索引(类似于字节串),您可以共享存储并且只需要遍历一次即可构建索引列表。算法不会改变,只是表示。对于这个特定的用例,使用 snoc 列表(二进制列表,但从列表的末尾而不是开头嵌套)也允许共享子列表,对吗?

      【讨论】:

      • 我认为比较清楚,他的问题针对的是普通的haskell 列表[]。 -1
      • 这取决于您是查看示例的语法还是所述的问题。鉴于接受的答案,对二进制列表的限制可能是有意的。但这不是纯函数算法的属性,甚至不是 Haskell 中的此类算法,只是这个特定的列表表示。
      • 是的,对二进制列表的限制是有意的。我本可以更清楚地说明这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-05
      • 2017-10-28
      • 2012-08-12
      • 2011-07-13
      • 2012-01-21
      相关资源
      最近更新 更多