資料結構:遞迴與迴圈
阿新 • • 發佈:2018-12-20
需要重複多次計算相同的問題,通常可以選擇用遞迴或者迴圈兩種不同的方法,遞迴是在函式內部用函式自身,迴圈則是通過設定計算的初始值及終止條件,在一個範圍內重複運算。 通常遞迴會比迴圈程式碼簡潔,更加容易實現。遞迴也有著顯著的缺點:1.遞迴由於是函式呼叫自身,而函式呼叫是有時間和空間的消耗:每一次函式呼叫都需要在記憶體棧中分配空間以儲存引數返回地址及臨時變數,壓棧出棧都需要時間,所以遞迴實現的效率不如迴圈好。2.遞迴中很多的運算可能是重複的。3.遞迴還存在一個嚴重的問題那就是棧溢位,每一次函式呼叫都需要在記憶體棧上分配空間,當遞迴的層級過多時,就會出現超出容量,從而到導致棧溢位。 下面劍指offer面試題10、14、47、48都用遞迴分析問題並基於迴圈寫程式碼。
/*面試題10:題目二:青蛙跳臺階問題 一隻青蛙一次可以跳上1級臺階,也可以跳上2級臺階,求該青蛙跳上n級的臺階總共有多少種跳法。 分析:把n級臺階時的跳法看成n的函式,記為法f(n),當n>2時,第一次跳的時候就有兩種,上1級後面剩下n-1級有f(n-1)種跳法 上2級後面剩下n-2級有f(n-2)種跳法 f(n)=f(n-1)+f(n-2),其實就是斐波那契數列 思路:1.在遞迴樹上會看到很多結點重複,並且重複的節點樹會隨著n的增大而增加,我們可以把得到的數列中間項儲存 2.從下往上算避免重複項o(n) 3.把斐波那契數列轉換成求矩陣的平方。 基於思路2,3寫了如下程式碼。 */ # include<stdio.h> # include <stdlib.h> int Fibonacci2(int n)//把遞迴的演算法用迴圈實現 { if(n == 1) { return 1; } else if(n == 0) { return 0; } else { int fib1 = 1;//記錄當前f(n-1) int fib2 = 0;//記錄當前f(n-2) int fibn = 0;//當前所求的分f(n) for(int i=2;i<=n;++i) { fibn = fib1 + fib2; fib1 = fib2; fib2 = fibn; } return fibn; } } #include <cassert> struct Matrix2By2//定義一個矩陣 { Matrix2By2( int m00 = 0, int m01 = 0, int m10 = 0, int m11 = 0):m_00(m00), m_01(m01), m_10(m10), m_11(m11) { } int m_00; int m_01; int m_10; int m_11; }; Matrix2By2 MatrixMultiply(const Matrix2By2& matrix1, const Matrix2By2& matrix2)//矩陣的乘方 { return Matrix2By2( matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10, matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11, matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10, matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11); } Matrix2By2 MatrixPower( int n) { assert(n > 0); Matrix2By2 matrix; if(n == 1) { matrix = Matrix2By2(1, 1, 1, 0); } else if(n % 2 == 0)//為偶數時 { matrix = MatrixPower(n / 2); matrix = MatrixMultiply(matrix, matrix); } else if(n % 2 == 1) { matrix = MatrixPower((n - 1) / 2); matrix = MatrixMultiply(matrix, matrix); matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0)); } return matrix; } int Fibonacci3(int n) { int result[2] = {0, 1}; if(n < 2) return result[n]; Matrix2By2 PowerNMinus2 = MatrixPower(n - 1); return PowerNMinus2.m_00; } void Test(int n, int expected) { if(Fibonacci2(n) == expected) printf("Test for %d in solution1 passed.\n", n); else printf("Test for %d in solution1 failed.\n", n); if(Fibonacci3(n) == expected) printf("Test for %d in solution2 passed.\n", n); else printf("Test for %d in solution2 failed.\n", n); } int main(int argc, char* argv[]) { Test(0, 0); Test(1, 1); Test(2, 1); Test(3, 2); Test(4, 3); Test(5, 5); Test(6, 8); Test(7, 13); Test(8, 21); Test(9, 34); Test(10, 55); Test(40, 102334155); return 0; }