Algorithm 对数运行时和尾部递归 在学校里,我一直在学习运行时和使用尾部递归等编写更高效的算法,还有一段时间,任务要求我们考虑计算幂的函数;p> (define (exp x n) (if (zero? n) 1 (* x (exp x (- n 1)))))

Algorithm 对数运行时和尾部递归 在学校里,我一直在学习运行时和使用尾部递归等编写更高效的算法,还有一段时间,任务要求我们考虑计算幂的函数;p> (define (exp x n) (if (zero? n) 1 (* x (exp x (- n 1))))),algorithm,optimization,recursion,runtime,racket,Algorithm,Optimization,Recursion,Runtime,Racket,我们的任务是编写一个带有运行时O(logn)的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)))))) 它来自于x^2n=(x^2)^n和x^2n+1=x*(x^2)^n 所以我一直在想一种实现尾部递

我们的任务是编写一个带有运行时O(logn)的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))))))
它来自于x^2n=(x^2)^n和x^2n+1=x*(x^2)^n

所以我一直在想一种实现尾部递归的方法来进一步优化这个函数,但我真的想不出一种方法来实现。回到我的问题,有什么
经验法则可以知道什么时候可以将多项式运行时算法作为对数运行时编写?


我问这个问题,是因为,写这篇文章很容易,因为它的运行时间是对数的,如果没有特别要求我这么做,我绝对不会想到要这么做。

关于你问题的第一部分:将过程转换为尾部递归形式相对简单,我们只需要传递一个额外的参数来累积答案。为了避免创建额外的过程,我将使用:


对于第二个问题:经验法则是——如果在进行递归调用时有一种方法可以将问题的大小减半(这样可以相应地计算结果),那么这是一个很好的迹象,表明它可能存在对数解。当然,这并不总是那么明显。

还有一个经典的例子:二进制搜索。在排序列表中搜索元素时,您知道每次“错过”时要搜索哪一半。非常感谢。我一定要好好读一读!是的,我在上学期的入门课程中学习了二进制搜索和二进制搜索树。我有点痴迷于efficiency@Plopperzz不客气!我添加了一个名为
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))))))