在monoid的帮助下将二次时间程序转换为线性时间程序?

时间:2019-01-19 09:03:10

标签: algorithm functional-programming time-complexity

当我正在阅读一篇有关Yoneda引理的论文时,我发现它与光学学的关系,我遇到了以下陈述:

  

... Cayley's   mono半定理(这是启用累加参数的技巧,   经常可以将二次时间程序变成线性时间程序)。

我感兴趣的部分是the trick ... quadratic-time... into a linear-time one。它是如何工作的?

P.S。我对Monoid和常用的数学符号很熟悉,因此如有必要,可以随时使用它,也可以坚持使用Haskell。

1 个答案:

答案 0 :(得分:2)

在H. Bird的原始论文之后,该主张的主要示例是简单链接列表的列表反转,可以定义为

reverse([a : x]) = append(reverse x, a)

在直接实现中,要将a附加到尾部x的反面,需要进行n-1查找操作才能找到结尾,并且该操作计数为reverse x,因此总工作量为(n-1)+...+2+1=n*(n-1)/2

线性实现使用append操作的非对称复杂度,因为append(x,y)的开销与x的长度成正比,而y的长度不起作用任何角色。作为append的部分运算,是列表append(x) y = append(x,y)上的同构。 现在将颠倒的列表表示为这些内态同构的结果

reverse([a1,a2,...,an])=append(an) ... append(a2) append(a1) []

,列表重建是从中进行的线性成本操作。先前的二次“主”成本在操作堆栈的管理中被“隐藏”。但是,最终并不需要这样做,因为结果列表的重建可以从提取第一个元素开始。这需要使用相同的野生伪代码的“累加元素”

reverse(x) = reverse_recursion(x,[])

其中

reverse_recursion([a : x], y) = reverse_recursion(x, [a : y])

reverse_recursion([], y) = y