簡體   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