繁体   English   中英

尾递归调用尾递归

[英]Tail recursion calling tail recursion

我正在尝试通过尾部递归来解决帕斯卡的三角形。 我知道要执行尾递归,函数调用语句应该是最后一条指令。 像这儿:

(defn pascal [line colum, acc]
  (if (or (= line 0) (= line colum) (= colum 0))
    (+ acc 1)
    (recur (dec line) colum
           (pascal (dec line) (dec colum), acc))))

我的问题是:由于我使用递归调用作为递归的参数,它仍然有效吗?

因为我不能代替这个:

(recur (dec line) colum
       (pascal (dec line) (dec colum), acc))))

对此:

(recur (dec line) colum
       (recur (dec line) (dec colum), acc))))

最好的祝福

您的调用中只有一半是通过尾递归进行的,因此另一半会破坏堆栈。 与此比较:

(defn factorial (n) 
  (if (= n 1)
      1
      (* n (factorial (n - 1)))))

这里(factorial (n - 1))需要在延续(* n <result>)之前完成,延续是递归运行时等待的堆栈帧。

这总比没有成为尾声更好,但是如果一切皆有可能那就更好了

也许我的答案与递归无关,而且这个问题与@Sylwester的答案完全不同,但是显示另一种解决此问题的方法仍然很有用。

假设Pascal三角形具有以下属性:

  1. 帕斯卡三角形的每一行的第一个和最后一个项目为“ 1”
  2. 第二倒数是行数
  3. 任何其他元素均可通过以下公式求解:

这意味着,您可以通过线性算法求解时间轴为O(n ^ 3)的帕斯卡三角形的任何元素。 它可能比O(n ^ 2)和递归的递归版本还差劲,但是它不会破坏堆栈,它使用了组合函数,我认为更好,因为它更简单,更安全。 所以,我们开始:

(defn naive-factorial[n]
  (reduce *' (range 1 (inc n))))

(defn combinatoric-formula[line pos]
  (if (<= pos line)
    (/ 
     (naive-factorial line) 
     (*' (naive-factorial pos) 
         (naive-factorial (- line pos))))))

如您所见,使用了naive-factorial函数,该函数乘以n ,从而得出O(n ^ 3)。 它与您的函数相同,但是没有任何递归。

对于帕斯卡三角形,还有许多方法可以用不同的方式解决它们。 如果您有很多时间,其中一些技巧非常棘手: rosettacode.org

同样在您的版本中,您可以通过+在clojure中使用int数学,请在任何情况下都可以在+'函数中使用in +' ,这会导致产生大量数字(假设这意味着加法会将您的值转换为biginteger类型,这将非常大数)。

此外,我翻译的@Sylwester介绍给CLOĴ茜方案版本:

(defn pascal [row col]
  (let [aux  
        (fn aux [tr tc prev acc]
          (cond (> tr row) (throw (.Exception "invalid input"))         
                (and (= col tc) (= row tr)) (+' (first prev) (second prev)); the next number is the answer
                (= tc tr) (recur (+' tr 1) 1 (cons 1 acc) '(1))                  ; new row 
                :else (recur tr               ; new column
                           (+' tc 1) 
                           (next prev)
                           (cons (+' (first prev) (second prev)) acc))))]
    (if (or (zero? col) (= col row))
      1
      (aux 2 1 '(1 1) '(1)))))

也许可以改进,但可以说明问题。 它计算了从第三行到提供的输入的前一个的整个三角形,然后得到了答案。 功能方法非常棒且纯粹。

这个版本的性能比线性版本差很多。 因此得到:

(time (combinatoric-formula 1000 100))
"Elapsed time: 2.73794 msecs" for linear version

(time (pascal 1000 100))
"Elapsed time: 135.426888 msecs" for tail recursion version

但是它仍然更加干净和凉爽;)

暂无
暂无

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

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