我正在尝试理解我为练习所阅读的解决方案,该练习定义了用于在Fibonacci序列中找到第n个数字的对数时间过程。计算机程序的结构和解释(SICP)中的问题是1.19。
SPOILER ALERT:此问题的解决方案将在下面讨论。
Fib(n)可以如下计算线性时间:以a = 1开始,b = 0.Fib(n)总是等于b的值。所以最初,当n = 0时,Fib(0)= 0.每次应用以下变换时,n增加1,Fib(n)等于b的值。
a <-- a + b
b <-- a
要在对数时间内执行此操作,问题描述会将转换T定义为转换
a' <-- bq + aq + ap
b' <-- bp + aq
其中p = 0且q = 1,最初,这个转换与上面的转换相同。
然后应用上述变换两次,练习指导我们根据a和b的原始值表达新值a''和b'。
a'' <-- b'q + a'q + a'p = (2pq + q^2)b + (2pq + q^2)a + (p^2 + q^2)a
b' <-- b'p + a'q = (p^2 + q^2)b + (2pq + q^2)a
然后,练习指的是将“转换”两次应用为“平方转换”的应用。我的理解是正确的吗?
本练习的解决方案应用了使用上述平方变换值的技术来生成以对数时间运行的解。问题如何在对数时间内运行?在我看来,每次我们使用应用平方变换的结果时,我们需要进行一次变换而不是两次变换。那么我们如何每次连续减少一半的步数呢?
来自schemewiki.org的解决方案发布在下面:
(define (fib n)
(fib-iter 1 0 0 1 n))
(define (fib-iter a b p q count)
(cond ((= count 0) b)
((even? count)
(fib-iter a
b
(+ (square p) (square q))
(+ (* 2 p q) (square q))
(/ count 2)))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1)))))
(define (square x) (* x x))
答案 0 :(得分:1)
然后,练习指的是将“转换”两次应用为“平方转换”的应用。我的理解是否正确?
是的,对变换进行平方意味着应用它两次或(如本练习的解决方案中的情况)找到另一个等效的变换以应用它两次。
问题如何以对数时间运行?在我看来,每次我们使用应用平方变换的结果时,我们需要进行一次变换而不是两次变换。那么我们如何每次连续减少一半的步数呢?
平方给定的变换使我们能够减少步数,因为p
和q
的值在平方变换中的增长速度远远快于原始变换。这类似于使用连续平方计算指数的方式比重复乘法更快。
那么我们如何每次连续减少一半的步数?
这是在给出的代码中。只要count
为偶数,就会在下一次迭代时传递(/ count 2)
以进行计数。无论在初始迭代中传递n
的值是什么,它都会在交替迭代(最差情况)下进行。
如果您希望在本练习中逐步推导出平方变换,可以在SICP Exercise 1.19: Computing Fibonacci numbers上阅读我的博文。
答案 1 :(得分:0)
@ Bill-the-Lizard提供了一个很好的证明,但是你允许自己被你对这个词的看法发生冲突&#34;两次&#34;和#34; square&#34;,与变换有关。
a)计算两次T项 - 也就是两次T - 是乘法的情况。乘法过程只是在每一步将T递增一个常数值的过程,其中常量值是原始术语本身。
相反:
b)给定的斐波纳契变换是一个过程,需要在每个操作步骤使用术语T的最新状态(与使用常数值相反)。 AND,操作的公式不是简单的增量,而是实际上是二次表达式(即涉及每个连续步骤的平方)。就像bill说的那样,如果你在调试器中单步执行它,这种连续的平方效果会变得非常清晰(我喜欢在某个地方卡住时手动计算一些简单的情况)。
以另一种方式思考这个过程:
如果您可以在下一步中覆盖当前距离的平方来到达目的地,但仍然以某种方式设法花费一定的时间来完成每一步,那么您将比那里更快地到达目的地如果你采取不断的步骤,每个步骤都是恒定的。