var f = function (x) { if (x < 2) return 1; //遞回終止條件 else return x * f(x - 1); //遞回呼叫過程 } console.log(f(5)); //返回5的階乘值為120在這個過程中,利用分支結構把遞迴結束條件和遞回運算分開。
function f (n) { //統計指定節點及其所有子節點的元素個數 var l = 0; //初始化計數變數 if (n.nodeType == 1) l ++; //如果是元素節點,則計數 var child = n.childNodes; //獲取子節點集合 for (var i = 0; i < child.length; i ++) { //遍歷所有子節點 l += f (child[i]); //遞回運算,統計當前節點下所有子節點數 } return l; //返回節點數 } window.onload = function () { console.log(f(document.body)); //返回2,即body和script兩個節點 }
function f (n,a,b,c) { if (n == 1) { //當為一片時,直接移動 document.write("移動 【盤子" + n + "】從【" + a + "柱】到【" + c + "柱】<br>"); } else { f (n - 1, a, c, b); //調整引數順序。讓引數a移給b document.write("移動 【盤子" + n + "】從【" + a + "柱】到【" + c + "柱】<br>"); f(n - 1, b, a, c); //調整順序,讓引數b移給c } } f (3, "A", "B", "C"); //呼叫漢諾塔函數執行結果如下:
移動【盤子1】從【A柱】到【C柱】
移動【盤子2】從【A柱】到【B柱】
移動【盤子1】從【C柱】到【B柱】
移動【盤子3】從【A柱】到【C柱】
移動【盤子1】從【B柱】到【A柱】
移動【盤子2】從【B柱】到【C柱】
移動【盤子1】從【A柱】到【C柱】
function f (n) { return (n == 1) ? 1 : n * f (n - 1); } console.log(f(5)); //120使用尾遞迴演算法後,則可以使用以下方法。
function f (n, a) { return (n == 1) ? a : f (n - 1, a * n); } console.log(f(5, 1)); //120當 n=5 時,線性遞回的遞迴過程如下。
f (5) = {5 * f(4)} = {5 * {4 * f(3) }} = {5 * {4 * {3 * f(2)}}} = {5 * {4 * {3 * {2 * f(1)}}}} = {5 * {4 * {3 * {2 *1}}}} = {5 * {4 * {3 *2}}} = {5 * {4 * 6} = {5 * 24} = 120而尾遞回的遞迴過程如下。
f (5) = f (5, 1) = f (4, 5) = f (3, 20) = f (2, 60) = f (1, 120) = 120很容易看出,普通遞回比尾遞回更加消耗資源,每次重複的過程呼叫都使得呼叫鏈條不斷加長,系統不得不使用棧進行資料儲存和恢復,而尾遞回就不存在這樣的問題,因為它的狀態完全由變數 n 和 a 儲存。
var n = 5; var w = 1; for (var i = 1; i <= 5; i ++) { w = w * i; } console.log(w);尾遞回由於直接返回值,不需要儲存臨時變數,所以效能不會產生線性增加,同時 JavaScript 引擎會將尾遞迴形式優化成非遞迴形式。
var fibonacci = function (n) { return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); }; console.log(fibonacci(19)); //4181嘗試傳入更大的數位,會發現遞回運算的次數加倍遞增,速度加倍遞減,返回值加倍放大。如果嘗試計算 100 的斐波那契數列,則瀏覽器基本癱瘓。
var fibonacci = function (n) { var a = [0, 1]; //記錄數列的陣列,第1、2個元素值確定 for (var i = 2; i <= n; i ++) { //從第 3 個數位開始迴圈 a.push(a[i - 2] + a[i - 1]); //計算新數位,並推入陣列 } return a[n]; //返回指定位數的數列結果 }; console.log(fibonacci(19)); //4181
var finbonacci = (function () { var memo = [0, 1]; var fib = function (n) { var result = memo[n]; if (typeof result !== 'number') { result = fib(n - 1) + fib(n - 2); memo[n] = result; } return result; }; return fib; }()); console.log(finbonacci(100)); //354224848179262000000在瀏覽器中測試,可以看到,求 100 的斐波那契數列基本上不會延遲。