關於遞迴和尾遞迴的原理

2021-08-31 20:18:31 字數 1543 閱讀 9999

[b][color=red]基礎很重要,這是永遠不變的真理。[/color][/b]

package sunfa;

public class digui

system.out.println("dg:");

dg(stack);

system.out.println("jc:");

system.out.println(jc(10));

system.gc();

system.out.println("wjc:");

int r = 1;

system.out.println(wjc(10, r));}/*

* 要求:棧內的元素要求從棧底開始列印。

* * 遞迴程式設計涉及到棧,也就是說比如乙個函式在執行的時候遇到了乙個遞迴函式,那麼它執行完了該遞迴函式後必須會執行遞迴函式後門的**,

* 反過來說就是這個遞迴函式後面的**必須在該遞迴函式執行完了後才能得到執行。

* * 原理:乙個函式執行過程中遇到遞迴(可能是自己或別人的),那麼它後面的**會進行入棧處理,如果這句入棧的**是這個函式的

* 最後一句**,那它肯定就只能最後被執行了。

* * 用途:比如並查集的路徑壓縮、平衡二叉樹的系列的路徑修復(下面的元素通過旋轉往上公升)都是基於遞迴的這個特點的。

*/private static void dg(stackstack)

}private static void fdg(stackstack) }/*

* 普通遞迴:

* jc(5)==>

* 5*jc(4)--->表示式入棧

* 5*4*jc(3)--->上一步的jc(4)是遞迴表示式,所以此處要先對其進行出棧,計算完jc(4)=4*jc(3)後在將表示式4*jc(3)入棧

* 5*4*3*jc(2)--->同上

* 5*4*3*2*jc(1)--->同上

* 5*4*3*2*jc(1) ==>由於n=1的時候函式返回的是乙個常數1,這個時候表示式變成5*4*3*2*1,不含有任何函式了,

* 所以開始計算該表示式的結果,計算結果的過程也是乙個出棧並計算的過程。

*/private static int jc(int n)

/** 尾遞迴:

* wjc(5,1)==>

* wjc(4,5)

* wjc(3,20)

* wjc(2,60)

* wjc(1,120)

* 尾遞迴是把每一步的結果都計算好了,所以不存在表示式入棧的缺點。

* * 很明顯,普通遞迴並沒有計算每一步的結果,而是到最後一步才去計算的, 它的每一步都包含乙個表示式,這個表示式

* 用棧來存放,當然棧頂的肯定是乙個表示式,所以每一步生成的表示式入棧後到下一步的時候把棧頂的表示式出棧,並解該

* 表示式,一直如此直到棧內不存在函式,這個時候才開始計算,如果沒有退出條件或因為棧已滿了那就會棧溢位。

* */

private static int wjc(int n, int r)

}

關於尾呼叫和尾遞迴

1 尾呼叫 指某個函式的最後一步是呼叫另乙個函式。例如 function a n 最後一步呼叫並不意味著在函式的尾部,只要是最後一步即可 function a n return c n 2 什麼樣的情況不是尾呼叫 情況一 function f x 解釋 呼叫g之後,還有賦值操作,故不屬於尾呼叫。情況...

遞迴和尾遞迴

c語言中編譯預處理的三種形式的命令 巨集定義,檔案包含,條件編譯命令。1 巨集定義主要是 define,undef 如下 define pi 3.1415926 不帶引數的巨集定義 define max a,b a b?a b 帶引數的巨集定義 說明 巨集定義在c語言與c 語言中是相通的。下面舉例說...

尾遞迴和線性遞迴

線性遞迴 fac 0 1 fac n n fac n 1 尾遞迴 fac 0,sum sum fac n,sum fac n 1,sum n 尾遞迴定義 函式最後一步呼叫自身,即最後一行 一定是對於自己的乙個遞迴呼叫。erlang尾遞迴這樣帶來的好處是可以讓編譯器做到將遞迴優化,轉化為跳轉指令而不是...