这是理查德·伯德(Richard Bird)的《从功能与思维》(Haskell)的思考(第158页)中的一个例子。有人可以解释一下1,2,3和4背后的原因吗?
编辑。 我了解由第一个定义形成的前三个方程。对于1.,为什么要求和?它与T(++)(n,m)=Θ(n)的关系如何? 对于第二个定义,我理解前两个语句。第三个(2.),为什么是k + n? 对于3和4。我完全迷路了
首先考虑concat的以下两个定义:
concat xss= foldr (++) [] xss
concat' xss = foldl (++) [] xss
如果xss是一个有限列表,则这两个定义是等效的。假设xss是长度为m的列表,长度为n。然后第一个定义给出
T(concat)(m, n) = T(foldr (++) [])(m, n),
T(foldr (++) [])(0, n) = Θ(1),
T(foldr (++) [])(m+1, n) = T(++)(n, mn) + T(foldr (++) [])(m, n).
之所以产生估计值T(++)(n,mn),是因为将长度为n的列表与长度为mn的列表连接在一起。由于T(++)(n,m)=Θ(n),我们得到
1. T(foldr (++) [])(m,n) = Σ_{k=0}^{m} Θ(n) = Θ(mn)
对于concat的第二个定义,我们有
T(concat')(m, n) = T(foldl (++))(0, m, n),
T(foldl (++))(k, 0, n) = O(1),
2. T(foldl (++))(k, m+1, n) = T(++)(k, n) + T(foldl (++))(k+n, m, n).
附加参数k表示foldl的第二个参数中累加列表的长度。这次我们获得了
3. T(foldl (++)) (k,m,n) = Σ_{j=0}{m-1} Θ(k+jn) = Θ(k+m^2n)
因此
4. T(concat')(m, n) = Θ(m_2 n)
答案 0 :(得分:1)
对于1.,为什么要求和?它与
T(++)(n, m) = Θ(n)
有何关系?
总和来自归纳定义。考虑这个独立的定义
g(0,n) = something
g(m+1,n) = f(m,n) + g(m,n)
通过归纳,我们得到
g(m,m)
= f(m-1,n) + g(m-1,n)
= f(m-1,n) + f(m-2,n) + g(m-2,n)
= f(m-1,n) + f(m-2,n) + f(m-3,n) + g(m-3,n)
= f(m-1,n) + f(m-2,n) + f(m-3,n) + ... + f(m-m,n) + g(m-m,n)
= f(m-1,n) + f(m-2,n) + f(m-3,n) + ... + f(m-m,n) + something
因此,结果是f(n,x)
的总和,其中x
有所不同,加上最后一项something
。
在原始定义中,g(m,n)
是T(foldr (++) [])(m, n)
,而
f(m,n) = T(++)(n, mn)
。最后一个术语无所谓,渐近。
对于第二个定义,我理解前两个语句。 第三个(2.),为什么是k + n?
在计算foldl (++) x ys
时,假设x
是长度为k
的列表,而ys
是长度为{{1}的列表的列表},其元素的长度为m+1
。
现在,递归n
方程为:
foldl
递归调用的成本包括(A)foldl (++) x (y:ys) = foldl (++) (x++y) ys
的成本,即temp = x++y
,和(B)T(++)(k, n)
的成本。对于(B),foldl (++) temp ys
的长度现在为temp
,而length x + length y = k+n
的长度为ys
(m
不受影响)。
所以,我们得到了
n
对于3.和4.我完全迷失了
在3.中,与对1.所做的一样,我们将T(foldl (++))(k, m+1, n)
= A + B
= T(++)(k, n) + T(foldl (++))(k+n, m, n).
的项与T(++)(k, n)
进行变化。请注意,每次递归,k
都会增加k
,因此我们得到
n
在4中,我们选择T(++)(k, n) + T(++)(k+n, n) + T(++)(k+n+n, n) + ...
= Σ_{j=0}{m-1} T(++)(k+jn, n)
= Σ_{j=0}{m-1} Θ(k+jn)
= Θ(k+m^2 n)
,因为在k=0
的定义中,我们最初选择了长度为concat'
的{{1}}。因此,只有x=[]
可以生存。