高阶函数的计算复杂性?

时间:2015-05-24 08:02:18

标签: haskell functional-programming complexity-theory higher-order-functions

映射和过滤器看起来像是线性O(n),因为它们只需要遍历列表一次,但它们的复杂性是否受传递函数的影响?例如下面两个相同顺序的例子?

map (+) list

map (complex_function) list

3 个答案:

答案 0 :(得分:5)

你似乎有一个(常见的)误解,即复杂性是n的函数。

什么是n

n只是衡量输入内容的一个参数。它可能不足以(或甚至是必要的)统计数据来描述您的输入 - 您可能需要其他变量来准确描述输入的复杂性。

因此,mapfiltern 中是线性。它们对其他变量的依赖取决于你传递的函数,但它们对n的依赖通常不会。

(脚注:是的,你可以将一个函数传递给mapfilter,因为它处理更多元素实际上执行了更多的工作,但那是无趣的除了我试图在这里做点之外。)

答案 1 :(得分:5)

在几乎所有情况下,当高阶函数的文档声明其复杂度为O(f(n))时,这假设高阶函数具有恒定的时间复杂度O(1)。此外,n的确切含义可能会有所不同,但如果没有明确说明,则应从上下文中明确说明:列表的长度,集合/映射中的元素/关联的数量,等等。

假设我们有一个名为g的更高阶函数g h ...,其中h是一个函数,而...是一阶数据。如果没有关于高阶函数g的任何其他信息,如果文档指出它为O(f(n)),则可以获得O(f(n)) * CostH更真实的最坏情况界限CostH代表H调用CostH一次的费用。

当然,h还取决于哪些参数开始传递给O(f(n)):在这里,我们所知道的是这些参数是在h时间构建的。很难对h的参数大小有一个有用的一般约束,因为,例如,如果foo :: Int -> Tree () foo 0 = Tree [] foo m = Tree [t,t] where t = foo (m-1) 将树作为输入,那么你可以在短时间内构建一个非常大的树: / p>

2^m

以上内容在m时间内构建了一个3^m个叶子的树(感谢分享)。这可以适应b^mb*m轻微保持g :: (a -> Int) -> [a] -> Int 复杂性。

但是,可能有一些方法可以利用参数化来恢复更有用的界限。例如,如果我们的订单功能具有类型

g h [...]

然后我们知道 h只能使用从列表中获取的参数调用sortBy h [...]。同样,库函数调用h只能使用(function(){ })(); 来比较提供列表中的两个元素。

但我不知道如何形式化和证明上述草拟的权利要求。很可能有一些关于这个主题的研究论文。

答案 2 :(得分:3)

有关复杂性和高阶函数的一些背景知识,请参阅,例如

霍夫曼,马丁。类别理论语义在高阶函数代数复杂类表征中的应用。

公牛。符号逻辑3(1997),没有。 4,469--486。 http://projecteuclid.org/euclid.bsl/1182353537