目錄遞迴**改為非遞迴**
遞迴是一種應用非常廣泛的演算法、程式設計技巧,如:
所有的遞迴都可以轉為非遞迴實現。
李柱明部落格:
遞迴的定義:
遞迴與棧結構:
優點:遞迴**的表達力很強,寫起來非常簡潔。
缺點:空間複雜度高。
有堆疊溢位的風險。
存在重複計算。
過多的函式呼叫會耗時較多。
遞迴需要滿足的兩個條件:
乙個問題可以分解為 n 個子問題。且子問題與原問題有著相同的形式。
存在遞迴終止條件。
編寫遞迴**的方法 1:
寫出遞推公式。
找到終止條件。
如中序遍歷:
遞推公式,左中右:in_order(c) = in_order(c_left) -> print c -> in_order(c_right)
終止條件:要遍歷的結點為空。即是傳進來的引數為空。
例子:假如這裡有 n 個台階,每次你可以跨 1 個台階或者 2 個台階,請問走這 n 個台階有多少種走法?
分析:
int f(int n)
編寫遞迴**的關鍵是,只要遇到遞迴,我們就把它抽象成乙個遞推公式,不用想一層層的呼叫關係,不要試圖用人腦去分解遞迴的每個步驟。
遞迴使用的是系統堆疊,如果系統堆疊溢位會造成系統性崩潰。
避免遞迴堆疊溢位方法:
限制遞迴深度。(採用全域性或者靜態變數記錄遞迴深度)
上面 f(3)就重複計算了,其實沒必要。
可以記錄每個 f(x) 的結果。在遞迴過程時優先遍歷這些結果,如果沒有直接結果才計算。
儲存 f(x) 的結果的資料結構有很多種,如雜湊表、鍊錶、樹等等。
所有的遞迴**都可以改為迭代迴圈的非遞迴寫法。
非遞迴方法思路:因為遞迴是借助棧來實現的,所以:
遞迴中發生變化的變數(遞迴返回值)-> 迴圈中每一次處理完相應變數存入 stack 中(push 進棧)。
遞迴中使用遞迴返回值 -> 迴圈中取出 stack 中的值進行處理(pop 出棧)。
既然入棧又出棧,那直接使用乙個固定空間,如函式棧,即是使用變數來儲存該值。
一般從尾遞迴開始反過來迭代迴圈。意思是迭代迴圈是迴圈遞迴**棧的流程。
如台階**:
int f(int n)
return ret;
}
資料結構 非遞迴
include stdafx.h include using namespace std 二叉樹鏈式儲存的標頭檔案 typedef char datatype 結點屬性值型別 typedef struct node 二叉樹結點的型別 bintnode typedef bintnode bintree...
遞迴轉非遞迴
題目描述 給定乙個列表,該列表中的每個要素要麼是個列表,要麼是整數。將其變成乙個只包含整數的簡單列表。如果給定的列表中的要素本身也是乙個列表,那麼它也可以包含列表。您在真實的面試中是否遇到過這個題?樣例給定 1,2,1,2 返回 1,2,1,2 給定 4,3,2,1 返回 4,3,2,1 挑戰請用非...
資料結構 演算法 遞迴
遞迴在較為高階的數演算法實現中是常用的,比如深度優先搜尋,暴力搜尋。下面展示較為簡單的遞迴 執行的過程中。public void recurisve recurisve system.out.println str test public void test 測試 依次輸入是 k i h a 依次輸...