简体   繁体   English

对数运行时和尾部递归

[英]Logarithmic runtime and tail recursion

In school, I have been learning about runtime and writing more efficient algorithms using tail recursion and the like, and a little while back an assignment asked us to consider the function for calculating powers; 在学校里,我一直在学习运行时,并使用尾部递归等方法编写更有效的算法,不久后,一个作业要求我们考虑用于计算功效的函数。

(define (exp x n)
    (if (zero? n) 1 (* x (exp x (- n 1)))))

and we were tasked with writing an exp function with a runtime O(log n), so this was my answer: 我们的任务是编写一个带有运行时O(log n)的exp函数,所以这就是我的答案:

(define (exp x n)
    (cond
        ((zero? n) 1)
        ((= 1 n) x)
        ((even? n) (exp (* x x) (/ n 2)))
        (else (* x (exp (* x x) (/ (- n 1) 2))))))

which simply comes from x^2n = (x^2)^n and x^2n+1 = x*(x^2)^n. 它只是来自x ^ 2n =(x ^ 2)^ n和x ^ 2n + 1 = x *(x ^ 2)^ n。

So I have been trying to think of a way to implement tail recursion to even further optimize this function, but I can't really think of a way to do this.Back to my question, Is there any sort of rule of thumb to know when you can write a polynomial runtime algorithm as a logarithmic runtime? 因此,我一直在尝试实现尾部递归的方法以进一步优化此功能,但我真的没有想到实现此功能的方法。回到我的问题, 是否有任何rule of thumb可知什么时候可以编写多项式运行时算法作为对数运行时?

I ask this, because, as easy as it was to write this in such a way that its runtime is logarithmic, I never would have thought to do it without having been specifically asked to do so. 我之所以这样问,是因为,以这样一种方式编写它的运行时间是对数的方式,这是如此容易,我从来没有想过要这样做,除非明确要求这样做。

Regarding the first part of your question: it's relatively simple to turn the procedure into tail-recursive form, we just have to pass an additional parameter to accumulate the answer. 关于问题的第一部分:将过程转换为尾递归形式相对简单,我们只需要传递一个附加参数即可累积答案。 To avoid creating an additional procedure I'll use a named let : 为避免创建其他过程,我将使用命名的let

(define (exp x n)
  (let loop ([x x] [n n] [acc 1])
    (cond
      ((zero? n) acc)
      ((= n 1) (* x acc))
      ((even? n) (loop (* x x) (/ n 2) acc))
      (else (loop (* x x) (/ (- n 1) 2) (* x acc))))))

And for the second question: the rule of thumb would be - if there's a way to halve the size of a problem at some point when making the recursive call (in such a way that the result can be computed accordingly), then that's a good sign that it might exist a logarithmic solution for it. 对于第二个问题:经验法则是-如果在进行递归调用时有某种方法可以将问题的大小减半(这样可以相应地计算结果),那么这很好表示它可能存在对数解。 Of course, that's not always so obvious. 当然,这并不总是那么明显。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM