Algorithm 生成列表所有前缀的最有效的纯函数算法是什么?

Algorithm 生成列表所有前缀的最有效的纯函数算法是什么?,algorithm,haskell,functional-programming,performance,Algorithm,Haskell,Functional Programming,Performance,有没有比这更好的办法?直观地说,在我看来,在纯函数式语言中,似乎无法得到低于O(n²)的算法,因为反向或追加必须应用n次。不过,我不知道如何证明这一点。我认为你是对的。不能共享列表的脊椎,因为所有尾部都不同。因此,如果对前缀列表进行充分评估,则将占用完整的Θ(n2)空间,这必须花费Ω(n2)时间才能生成 请注意,您编写的函数(更懒惰的版本)可以在Data.List中作为inits使用 不过你可以做一个简洁的优化。这个方程式适用于: prefixes ls = zipWith take [1 ..

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

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

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

不过你可以做一个简洁的优化。这个方程式适用于:

prefixes ls = zipWith take [1 .. length ls] (repeat ls)

scanl
以线性时间运行。因此,如果你可以将你想对每个前缀做的事情用左折叠的方式表达出来,那么你就可以避免构建前缀列表的二次复杂度。

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

我认为相对清楚的是,他的问题针对的是一个普通的haskell列表
[
-1这取决于您是在看示例的语法还是所述的问题。鉴于已接受的答案,可能有意对二进制列表进行限制。但这不是纯函数算法的特性,甚至不是Haskell中此类算法的特性,只是这种特殊的列表表示。是的,对二进制列表的限制是有意的。我本来可以说得更清楚的。
map (foldl f z) . inits = scanl f z