繼上篇博文裡介紹的c語言常見基礎演算法,本篇在於演算法的思路的整理和常見的演算法程式設計實現。
【定義】遞迴具體用法其實就是讓你把乙個問題分解成很多個類似的情況,雖然你要解決這個問題非常難,莫名其妙,要你想幾年,但是把他一直遞迴分解,就變成很好理解的單種情況,而你整個問題又是跟這個單種情況類似,把整個問題通過遞迴呼叫一層一層分解到最低階簡單的那種情況,就是你所需要理解的了。
乙個函式在它的函式體內呼叫它自身稱為遞迴呼叫。這種函式稱為遞迴函式。c語言允許函式的遞迴呼叫。在遞迴呼叫中,主調函式又是被調函式。執行遞迴函式將反覆呼叫其自身,每呼叫一次就進入新的一層。
常見的用法:1、斐波那契數列
// 計算fibonaci數列---2
intfibonaci_2
(int n)
else}0
1123
58...
.或者定義乙個公有的temp,返回該值。邊界條件可以是n=
0\n=
1
2、階乘
n!=1 (n=0,1)
n!=n*(n-1)! (n>1)
(n-1)!=(n-1)*(n-2)!
具體如下
long ff(int n)
經過n次入棧後,剩下n=1的已知值,後續全部相乘,直接得到答案,返回結果,出棧一次
3、倒序輸出字串、數字轉字元等
void
alpha_exchange_2
(void)}
void
alpha_exchange_3
(void
)alpha_exchange_3()
;printf
("%c"
,temp)
;}
void
binary_to_ascii
(unsigned
int value)
該函式出棧了n次,將每一次傳入引數出棧計算,都是結果的一部分
4、翻轉鍊錶,翻轉佇列
struct listnode*
reverselist
(struct listnode* head)
}
//遞迴實現
struct node *
reverse
(struct node *phead)
struct node *p = phead -> pnext;
struct node *pnewhead =
reverse
(p);
p -> pnext = phead;
phead ->pnext =
null
;return pnewhead;
}
【優化方法介紹(尾遞迴)】
從我給出的第一演算法可以看出,先進棧再出棧,遞迴的效率是很低的。速度上完全比不上迭代(迴圈)。但是尾遞迴引入了乙個新的函式引數,用這個新的函式引數來記錄中間值。普通遞迴階乘fac(x),就1個x而已,尾遞迴用2個引數fac(x,y),y存放階乘值。
int
fac(
int x,
int y)
intff
(int x)
intfac
(int x,
int y)
else
}對於這個程式我們先看函式ff,函式ff其實是對fac的乙個封裝函式,
純粹是為了輸入方便設計的,通過呼叫ff
(x)來呼叫fac
(x,1
),
這裡常數1就是當x=1的時候階乘值了,我通過走一遍當x=3時的值即為3!來說明一下。首先ff(3),x!=0,執行fac(3,1).第一次呼叫fac,x=3,y=1,x!=1,呼叫fac(x-1,yx),新的x=2,y=3*1=3,這裡可以看到,y已經累計了一次階乘值了,你會發現這個遞迴更類似於迭代了。事實上我們用了y記錄了普通遞迴時候,出棧的乘積,所以減少了出棧後的步驟。
【推薦文章】
本博文詳細介紹了遞迴的入棧和出棧的過程,需要特別強調的是遞迴的結束條件以及選用遞迴的傳入引數。
在呼叫函式之後的**是在函式返回後執行的,因此會層次的呼叫出棧的變數。
遞迴演算法思想
在知乎上面搜尋遞迴,但是普遍的回答是業務開發中不常涉及,和for迴圈差不多,消耗效能太大,不推薦使用。本著不服管的性格,我差了一些有用的資料,和大家分享下,遞迴的演算法和使用場景。為什麼要用遞迴 程式設計裡面估計最讓人摸不著頭腦的基本演算法就是遞迴了。很多時候我們看明白乙個複雜的遞迴都有點費時間,尤...
遞迴演算法思想
遞迴演算法就是在程式中不斷反覆呼叫自身來達到求解的方法。這裡的重點就是呼叫自身,這就是要求待求解的問題能夠分解為相同問題的乙個子問題。這樣通過多次遞迴呼叫,便可以完成求解。函式的遞迴呼叫分兩種情況 直接遞迴和間接遞迴。直接遞迴,即在函式中呼叫函式本身。間接遞迴,即間接呼叫乙個函式,如fun 1呼叫f...
演算法 遞迴思想
給定乙個字串 該字串沒有相同的字母 使用遞迴的方式列印出這個字串所包含字母的所有組合方式 package test1 public class num f c,0 c為待遞迴陣列,先確定第乙個字元,再確定第二個.b為所有已確定字元位的後乙個字元位 static void f char c,int b...