很久找不到學習的平衡點,似乎有目的性的去解決問題尋求方法獲得知識會比直接吸取知識要有趣,更印象深刻,這些都是我爬過的坑,以此銘記在心。
1. 隊列在程序調用時必不可少,因此遞歸離不開隊列。×
遞歸是棧實現的。棧是先進後出,也就是上次遞歸調用的時候,保存在棧頂。在返回的時候出棧,所以是遞歸依靠棧實現的
遞歸的定義:遞歸調用是一種特殊的嵌套調用,是某個函數調用自己或者是調用其他函數後再次調用自己的,只要函數之間互相調用能產生循環的則一定是遞歸調用
遞歸的特點:
- 函數要直接或間接調用自身。
- 要有遞歸終止條件檢查,即遞歸終止的條件被滿足後,則不再調用自身函數,函數的調用原則和數據結構棧的實現是相一致。(類似於不斷壓棧,直到棧滿,作爲終止條件)
- 如果不滿足遞歸終止的條件,則調用涉及遞歸調用的表達式。在調用函數自身時,有關終止條件的參數要發生變化,而且需向遞歸終止的方向變化。
2. 以下程序是用來計算兩個非負數之間的最大公約數:
long long gcd(long long x, long long y) {
if (y == 0)
return x;
else
return gcd(y, x % y);
}
我們假設x,y中最大的那個數的長度爲n,基本運算時間複雜度爲O(1),那麼該程序的時間複雜度爲o(log n)
求最大公約數用的是輾轉相除法(歐幾里得算法):兩個整數的最大公約數等於其中較小的那個數和兩數相除餘數的最大公約數,所以是O(log n)。最大公約數還有Stein算法計算
3. 設有遞歸算法如下,
int x(int n)
{
if(n<=3)
return 1;
else
return x(n-2)+x(n-4)+1;
}
試問計算x(x(8))時需要計算18
次x函數。
根據題意,易得x(3) = x(2) = x(1) = x(0) = 1
x(8) = x(6) +x(4) +1
= x(4) + x(2) +1 + x(2) + x(0) +1 + 1
= x(2) + x(0) +1 + 1 + 1 +1 + 1 +1 + 1
= 9
x(8) 這個就調用了9次函數x(int n)
同理可得x(9)也是調用了9次函數x(int n)
所以總共18次。
4. 4個圓盤的Hanoi塔,總的移動次數爲15
Hanoi 問題的理解是:
- 先把上面n-1個圓盤移到第二個柱子上(共f(n-1)步)
- 再把最後一個圓盤移到第三個柱子(共1步)
- 再把第二柱子上的圓盤移動到第三個柱子上(共f(n-1)步)
於是得出其遞推方程:f(n)=f(n-1)+1+ f(n-1)=2*f(n-1)+1
5.對遞歸程序的優化的一般的手段爲尾遞歸優化
常見的優化手段有尾遞歸,迭代,循環
尾遞歸:在每一次遞歸的過程中保持了上一次計算的狀態,也就是“線性迭代過程”
尾遞歸和一般的遞歸不同在對內存的佔用,普通遞歸創建stack累積而後計算收縮,尾遞歸只會佔用恆量的內存(和迭代一樣)
舉個例子,計算n的階乘
//線性遞歸
long Rescuvie(long n) {
return (n == 1) ? 1 : n * Rescuvie(n - 1);
}
//尾遞歸
long TailRescuvie(long n, long a) {
return (n == 1) ? a : TailRescuvie(n - 1, a * n);
}
long TailRescuvie(long n) {//封裝用的
return (n == 0) ? 1 : TailRescuvie(n, 1);
}