什么是遞歸調用
遞歸調用是一種特殊的嵌套調用,是某個函數調用自己或者是調用其他函數后再次調用自己的,只要函數之間互相調用能產生循環的則一定是遞歸調用,遞歸調用一種解決方案,一種是邏輯思想,將一個大工作分為逐漸減小的小工作。
遞歸函數特點:
1、函數要直接或間接調用自身。
2、要有遞歸終止條件檢查,即遞歸終止的條件被滿足后,則不再調用自身函數。
3、如果不滿足遞歸終止的條件,則調用涉及遞歸調用的表達式。在調用函數自身時,有關終止條件的參數要發生變化,而且需向遞歸終止的方向變化。
擴展資料:
遞歸調用的過程:
遞歸調用之前的語句是從上到下的,函數調用之后的語句呢是從下到上的,因為后面的語句要等最下層或者最里面最后調用的那個函數執行之后不再調用了開始執行,然后返回上一層的時候再執行上一層函數調用后面的語句。并且特別注意的是,每次函數返回后直接就是函數調用后面的語句。
遞歸其實就是利用了函數調用的一些特點,很巧妙的不斷調用自己,把一個很大的問題分成了很多部分,讓每一個函數解決一部分,并且上一層的結果編譯器給我們保留了起來,返回的時候還能用。
所以遞歸調用一定要是每深入一層都會把問題變得越來越小,而且最后能解決,不然就會無限制的調用自己,形成一個無限的循環,最后造成棧的溢出,最后程序崩潰。
參考資料來源:百度百科-遞歸調用
什么是遞歸調用,詳細點
C通過運行時堆棧支持遞歸函數的實現。遞歸函數就是直接或間接調用自身的函數。
許多教科書都把計算機階乘和菲波那契數列用來說明遞歸,非常不幸我們可愛的著名的老潭老師的《C語言程序設計》一書中就是從階乘的計算開始的函數遞歸。導致讀過這本經書的同學們,看到階乘計算第一個想法就是遞歸。但是在階乘的計算里,遞歸并沒有提供任何優越之處。在菲波那契數列中,它的效率更是低的非常恐怖。
這里有一個簡單的程序,可用于說明遞歸。程序的目的是把一個整數從二進制形式轉換為可打印的字符形式。例如:給出一個值4267,我們需要依次產生字符‘4’,‘2’,‘6’,和‘7’。就如在printf函數中使用了%d格式碼,它就會執行類似處理。
我們采用的策略是把這個值反復除以10,并打印各個余數。例如,4267除10的余數是7,但是我們不能直接打印這個余數。我們需要打印的是機器字符集中表示數字‘7’的值。在ASCII碼中,字符‘7’的值是55,所以我們需要在余數上加上48來獲得正確的字符,但是,使用字符常量而不是整型常量可以提高程序的可移植性。‘0’的ASCII碼是48,所以我們用余數加上‘0’,所以有下面的關系:
‘0’+ 0 =‘0’
‘0’+ 1 =‘1’
‘0’+ 2 =‘2’
...
從這些關系中,我們很容易看出在余數上加上‘0’就可以產生對應字符的代碼。接著就打印出余數。下一步再取商的值,4267/10等于426。然后用這個值重復上述步驟。
這種處理方法存在的唯一問題是它產生的數字次序正好相反,它們是逆向打印的。所以在我們的程序中使用遞歸來修正這個問題。
我們這個程序中的函數是遞歸性質的,因為它包含了一個對自身的調用。乍一看,函數似乎永遠不會終止。當函數調用時,它將調用自身,第2次調用還將調用自身,以此類推,似乎永遠調用下去。這也是我們在剛接觸遞歸時最想不明白的事情。但是,事實上并不會出現這種情況。
這個程序的遞歸實現了某種類型的螺旋狀while循環。while循環在循環體每次執行時必須取得某種進展,逐步迫近循環終止條件。遞歸函數也是如此,它在每次遞歸調用后必須越來越接近某種限制條件。當遞歸函數符合這個限制條件時,它便不在調用自身。
在程序中,遞歸函數的限制條件就是變量quotient為零。在每次遞歸調用之前,我們都把quotient除以10,所以每遞歸調用一次,它的值就越來越接近零。當它最終變成零時,遞歸便告終止。
/*接受一個整型值(無符號0,把它轉換為字符并打印它,前導零被刪除*/
#include <stdio.h>
int binary_to_ascii( unsigned int value)
{
unsigned int quotient;
quotient = value / 10;
if( quotient != 0)
binary_to_ascii( quotient);
putchar ( value % 10 + '0' );
}
遞歸是如何幫助我們以正確的順序打印這些字符呢?下面是這個函數的工作流程。
1. 將參數值除以10
2. 如果quotient的值為非零,調用binary-to-ascii打印quotient當前值的各位數字
3. 接著,打印步驟1中除法運算的余數
注意在第2個步驟中,我們需要打印的是quotient當前值的各位數字。我們所面臨的問題和最初的問題完全相同,只是變量quotient的值變小了。我們用剛剛編寫的函數(把整數轉換為各個數字字符并打印出來)來解決這個問題。由于quotient的值越來越小,所以遞歸最終會終止。
一旦你理解了遞歸,閱讀遞歸函數最容易的方法不是糾纏于它的執行過程,而是相信遞歸函數會順利完成它的任務。如果你的每個步驟正確無誤,你的限制條件設置正確,并且每次調用之后更接近限制條件,遞歸函數總是能正確的完成任務。
但是,為了理解遞歸的工作原理,你需要追蹤遞歸調用的執行過程,所以讓我們來進行這項工作。追蹤一個遞歸函數的執行過程的關鍵是理解函數中所聲明的變量是如何存儲的。當函數被調用時,它的變量的空間是創建于運行時堆棧上的。以前調用的函數的變量扔保留在堆棧上,但他們被新函數的變量所掩蓋,因此是不能被訪問的。
當遞歸函數調用自身時,情況于是如此。每進行一次新的調用,都將創建一批變量,他們將掩蓋遞歸函數前一次調用所創建的變量。當我追蹤一個遞歸函數的執行過程時,必須把分數不同次調用的變量區分開來,以避免混淆。
什么叫做嵌套調用?什么叫做遞歸調用
嵌套調用:
所謂嵌套調用就是在一個函數中調用其他函數的過程叫做函數的嵌套。C++中函數的定義是平行的,除了main()以外,都可以互相調用。函數不可以嵌套定義,但可以嵌套調用。比如函數1調用了函數2,函數2調用了函數3,這便形成了函數的嵌套調用。
遞歸調用:
在調用一個函數的過程中又直接或間接第調用該函數本身的這一現象,叫做函數的遞歸調用。
遞歸可以分為直接遞歸和間接遞歸調用。直接遞歸調用時在調用函數的過程中又調用該函數本身;間接遞歸調用是在調用f1()函數的過程中調用f2()函數,而f2()函數中又需要調用f1()。
遞歸方法是從結果出發,歸納出后一結果與前一結果直到初值為止存在的關系,要求通過分析得到:初值+遞歸函數,然后設計一個函數,這個函數不斷使用下一級值調用自身,直到結果已知處。設計遞歸函數一般選擇控制結構。
遞歸調用的遞歸詳解
一個函數的運行期間調用另一個函數時,在運行被調用函數之前,系統需要完成3件事情:
(1)將所有的實參、返回地址等信息傳遞給被調用函數保存;
(2)為被調用函數的局部變量分配存儲區;
(3)將控制轉移到被調函數的入口。 而從被調用函數返回調用函數之前,系統也應完成3件工作:
(1)保存被調函數的計算結果;
(2)釋放被調函數的數據區;
(3)依照被調函數保存的返回地址將控制轉移到調用函數。當有多個函數構成嵌套調用時,按照后調用先返回的原則。 所有遞歸函數的結構都是類似的。
(1)函數要直接或間接調用自身。
(2)要有遞歸終止條件檢查,即遞歸終止的條件被滿足后,則不再調用自身函數。
(3)如果不滿足遞歸終止的條件,則調用涉及遞歸調用的表達式。在調用函數自身時,有關終止條件的參數要發生變化,而且需向遞歸終止的方向變化。 函數的調用原則和數據結構棧的實現是相一致。也說明函數調用是通過棧實現的。
直接遞歸調用和間接遞歸調用區別
1、區別就是直接遞歸調用調用的是函數本身而間接遞歸調用調用的是其他函數。例如:在函數a(或過程)中直接引用(調用)函數a本身就是直接遞歸調用。在函數a(或過程)中調用另外一個函數b,而該函數b又引用(調用)了函數a就是間接遞歸調用。
2、直接遞歸是在A函數中嵌套使用A函數然后有一個停止該函數的條件;間接遞歸是在A函數中調用B函數,然后在B函數中調用A函數,實現遞歸。
擴展資料
遞歸調用就是在當前的函數中調用當前的函數并傳給相應的參數,這是一個動作,這一動作是層層進行的,直到滿足一般情況的的時候,才停止遞歸調用,開始從最后一個遞歸調用返回。
遞歸函數特點:
1、函數要直接或間接調用自身。
2、要有遞歸終止條件檢查,即遞歸終止的條件被滿足后,則不再調用自身函數。
3、如果不滿足遞歸終止的條件,則調用涉及遞歸調用的表達式。在調用函數自身時,有關終止條件的參數要發生變化,而且需向遞歸終止的方向變化。
遞歸調用
首先原代碼中的fun函數要么改為void返回類型,要么在*s=1前腰加上return否者程序編譯會出錯。
fun中有指針變量,可以算是一個全局變量,故,在分析的時候只需要分析在遞歸的最后一共有幾個滿足fun(1,&f)或fun(0,&f)的函數。每一個fun(0||1,&f)加1。
例如fun(2,&f)則結果為fun(1,&f)+fun(0,&f)=2。fun(3,&f)結果為=(fun(2,&f)+fun(1,&f))=3.fun(4,&f)=fun(3,&f)+fun(2,&f)=5.fun(5,&f)=fun(4,&f)+fun(3,&f)=8. fun(6,&f)=fun(5,&f)fun(4,&f)=8+5=13