① c語言遞歸函數的問題
通過分析這個代碼,建立了如圖的樹。
1、當進去A時,num = 1;
2、接著往左進去B,num = 2;
3、往B左邊及右邊因為是NULL直接返回2處,再返回到1處;
4、接著往A右邊C,此時num=3,這里把返回值C壓入寄存器RAX,代碼返回到A,但是最上層A處沒有接收返回值,此時A退出,main函數從RAX取出返回值賦值給變數a。
這就是整個調用過程,這里返回值並不是最上層的返回值,是C的返回值,之所以能得到這個值是這個程序沒有同步其它地方使用了RAX寄存器,它的值沒有被修改。
② C語言中的遞歸是什麼意思
程序調用自身的編程技巧稱為遞歸( recursion)。遞歸做為一種演算法在程序設計語言中廣泛應用。 一個過程或函數在其定義或說明中有直接或間接調用自身的一種方法,它通常把一個大型復雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解。
遞歸策略只需少量的程序就可描述出解題過程所需要的多次重復計算,大大地減少了程序的代碼量。遞歸的能力在於用有限的語句來定義對象的無限集合。
一般來說,遞歸需要有邊界條件、遞歸前進段和遞歸返回段。當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。
(2)c語言遞歸過程擴展閱讀:
遞歸的應用
1、數據的定義是按遞歸定義的。(Fibonacci函數)
2、問題解法按遞歸演算法實現。這類問題雖則本身沒有明顯的遞歸結構,但用遞歸求解比迭代求解更簡單,如Hanoi問題。
3、數據的結構形式是按遞歸定義的。
遞歸的缺點
遞歸演算法解題相對常用的演算法如普通循環等,運行效率較低。因此,應該盡量避免使用遞歸,除非沒有更好的演算法或者某種特定情況,遞歸更為適合的時候。在遞歸調用的過程當中系統為每一層的返回點、局部量等開辟了棧來存儲。遞歸次數過多容易造成棧溢出等。
③ C語言 遞歸程序 求解
遞歸函數就是做了一件事:求和
遞歸過程如下:
第一次進入:n==3, 執行的是 p[0]+f(&p[1],2);這樣的話會繼續調用函數f,也就有了第二次進入。
第二次進入:表達式變成了p[0]+p[1]+f[&p[1],1],這樣的話會繼續調用函數f,也就有了第三次進入。
第三次進入:n==1, p[0]+p[1]+p[2].
return (p[0]+f(&p[1],2)=p[0]+p[1]+f[&p[1],1]=p[0]+p[1]+p[2])-->return p[0]+p[1]+p[2]
遞歸一般是出於效率的要求,當然你這個沒什麼影響。遞歸也不是用在這里的。看遞歸要干什麼很簡單,看兩點:1.遞歸退出條件是什麼,退出時的返回值;2.遞歸時在做什麼。
④ c語言遞歸演算法
用遞歸法計算n!
用遞歸法計算n!可用下述公式表示:
n!=1 (n=0,1)
n×(n-1)! (n>1)
按公式可編程如下:
long ff(int n)
{
long f;
if(n<0) printf("n<0,input error");
else if(n==0||n==1) f=1;
else f=ff(n-1)*n;
return(f);
}
main()
{
int n;
long y;
printf("\ninput a inteager number:\n");
scanf("%d",&n);
y=ff(n);
printf("%d!=%ld",n,y);
}
程序中給出的函數ff是一個遞歸函數。主函數調用ff 後即進入函數ff執行,如果n<0,n==0或n=1時都將結束函數的執行,否則就遞歸調用ff函數自身。由於每次遞歸調用的實參為n-1,即把n-1的值賦予形參n,最後當n-1的值為1時再作遞歸調用,形參n的值也為1,將使遞歸終止。然後可逐層退回。
下面我們再舉例說明該過程。設執行本程序時輸入為5,即求5!。在主函數中的調用語句即為y=ff(5),進入ff函數後,由於n=5,不等於0或1,故應執行f=ff(n-1)*n,即f=ff(5-1)*5。該語句對ff作遞歸調用即ff(4)。
進行四次遞歸調用後,ff函數形參取得的值變為1,故不再繼續遞歸調用而開始逐層返回主調函數。ff(1)的函數返回值為1,ff(2)的返回值為1*2=2,ff(3)的返回值為2*3=6,ff(4)的返回值為6*4=24,最後返回值ff(5)為24*5=120。
⑤ c語言遞歸函數
遞歸(recursion)就是子程序(或函數)直接調用自己或通過一系列調用語句間接調用自己,是一種描述問題和解決問題的基本方法。
遞歸通常用來解決結構自相似的問題。所謂結構自相似,是指構成原問題的子問題與原問題在結構上相似,可以用類似的方法解決。具體地,整個問題的解決,可以分為兩部分:第一部分是一些特殊情況,有直接的解法;第二部分與原問題相似,但比原問題的規模小。實際上,遞歸是把一個不能或不好解決的大問題轉化為一個或幾個小問題,再把這些小問題進一步分解成更小的問題,直至每個小問題都可以直接解決。因此,遞歸有兩個基本要素:
(1)邊界條件:確定遞歸到何時終止,也稱為遞歸出口。
(2)遞歸模式:大問題是如何分解為小問題的,也稱為遞歸體。遞歸函數只有具備了這兩個要素,才能在有限次計算後得出結果
漢諾塔問題:對漢諾塔問題的求解,可以通過以下3個步驟實現:
(1)將塔上的n-1個碟子藉助塔C先移到塔B上;
(2)把塔A上剩下的一個碟子移到塔C上;
(3)將n-1個碟子從塔B藉助塔A移到塔C上。
在遞歸函數中,調用函數和被調用函數是同一個函數,需要注意的是遞歸函數的調用層次,如果把調用遞歸函數的主函數稱為第0層,進入函數後,首次遞歸調用自身稱為第1層調用;從第i層遞歸調用自身稱為第i+1層。反之,退出第i+1層調用應該返回第i層。採用圖示方法描述遞歸函數的運行軌跡,從中可較直觀地了解到各調用層次及其執行情況,具體方法如下:
(1)寫出函數當前調用層執行的各語句,並用有向弧表示語句的執行次序;
(2)對函數的每個遞歸調用,寫出對應的函數調用,從調用處畫一條有向弧指向被調用函數入口,表示調用路線,從被調用函數末尾處畫一條有向弧指向調用語句的下面,表示返迴路線;
(3)在返迴路線上標出本層調用所得的函數值。n=3時漢諾塔演算法的運行軌跡如下圖所示,有向弧上的數字表示遞歸調用和返回的執行順序
三、遞歸函數的內部執行過程
一個遞歸函數的調用過程類似於多個函數的嵌套的調用,只不過調用函數和被調用函數是同一個函數。為了保證遞歸函數的正確執行,系統需設立一個工作棧。具體地說,遞歸調用的內部執行過程如下:
(1)運動開始時,首先為遞歸調用建立一個工作棧,其結構包括值參、局部變數和返回地址;
(2)每次執行遞歸調用之前,把遞歸函數的值參和局部變數的當前值以及調用後的返回地址壓棧;
(3)每次遞歸調用結束後,將棧頂元素出棧,使相應的值參和局部變數恢復為調用前的值,然後轉向返回地址指定的位置繼續執行。
上述漢諾塔演算法執行過程中,工作棧的變化如下圖所示,其中棧元素的結構為(返回地址,n值,A值,B值,C值),返回地址對應演算法中語句的行號,分圖的序號對應圖中遞歸調用和返回的序號
我可以幫助你,你先設置我最佳答案後,我網路Hii教你。
⑥ C語言關於函數的遞歸
你的遞歸程序是錯的,我轉來個對的,帶講解的,你看看。
語言函數的遞歸和調用
一、基本內容:
C語言中的函數可以遞歸調用,即:可以直接(簡單遞歸)或間接(間接遞歸)地自己調自己。
要點:
1、C語言函數可以遞歸調用。
2、可以通過直接或間接兩種方式調用。目前只討論直接遞歸調用。
二、遞歸條件
採用遞歸方法來解決問題,必須符合以下三個條件:
1、可以把要解決的問題轉化為一個新問題,而這個新的問題的解決方法仍與原來的解決方法相同,只是所處理的對象有規律地遞增或遞減。
說明:解決問題的方法相同,調用函數的參數每次不同(有規律的遞增或遞減),如果沒有規律也就不能適用遞歸調用。
2、可以應用這個轉化過程使問題得到解決。
說明:使用其他的辦法比較麻煩或很難解決,而使用遞歸的方法可以很好地解決問題。
3、必定要有一個明確的結束遞歸的條件。
說明:一定要能夠在適當的地方結束遞歸調用。不然可能導致系統崩潰。
三、遞歸實例
例:使用遞歸的方法求n!
當n>1時,求n!的問題可以轉化為n*(n-1)!的新問題。
比如n=5:
第一部分:5*4*3*2*1
n*(n-1)!
第二部分:4*3*2*1
(n-1)*(n-2)!
第三部分:3*2*1
(n-2)(n-3)!
第四部分:2*1
(n-3)(n-4)!
第五部分:1
(n-5)!
5-5=0,得到值1,結束遞歸。
源程序:
fac(int
n)
{int
t;
if(n==1)||(n==0)
return
1;
else
{
t=n*fac(n-1);
return
t;
}
}
main(
)
{int
m,y;
printf(「Enter
m:」);
scanf(「%d」,&m);
if(m<0)
printf(「Input
data
Error!\n」);
else
{y=fac(m);
printf(「\n%d!
=%d
\n」,m,y);
}
}
四、遞歸說明
1、當函數自己調用自己時,系統將自動把函數中當前的變數和形參暫時保留起來,在新一輪的調用過程中,系統為新調用的函數所用到的變數和形參開辟另外的存儲單元(內存空間)。每次調用函數所使用的變數在不同的內存空間。
2、遞歸調用的層次越多,同名變數的佔用的存儲單元也就越多。一定要記住,每次函數的調用,系統都會為該函數的變數開辟新的內存空間。
3、當本次調用的函數運行結束時,系統將釋放本次調用時所佔用的內存空間。程序的流程返回到上一層的調用點,同時取得當初進入該層時,函數中的變數和形參所佔用的內存空間的數據。
4、所有遞歸問題都可以用非遞歸的方法來解決,但對於一些比較復雜的遞歸問題用非遞歸的方法往往使程序變得十分復雜難以讀懂,而函數的遞歸調用在解決這類問題時能使程序簡潔明了有較好的可讀性;但由於遞歸調用過程中,系統要為每一層調用中的變數開辟內存空間、要記住每一層調用後的返回點、要增加許多額外的開銷,因此函數的遞歸調用通常會降低程序的運行效率。
五、程序流程
fac(int
n)
/*每次調用使用不同的參數*/
{
int
t;
/*每次調用都會為變數t開辟不同的內存空間*/
if(n==1)||(n==0)
/*當滿足這些條件返回1
*/
return
1;
else
{
t=n*fac(n-1);
/*每次程序運行到此處就會用n-1作為參數再調用一次本函數,此處是調用點*/
return
t;
/*只有在上一句調用的所有過程全部結束時才運行到此處。*/
}
}
⑦ C語言的遞歸過程!
這個東西首先,你要確定遞歸出口。沒有出口,你就算不出結果的。
從你給出的代碼片段來看,出口應該是n==0,也就說rfcat(0)=1這樣。
那麼所謂的第一層到底哪裡算第一層呢?
首先程序從主函數開始運行,系統建立了一個存儲運行狀態的棧。在系統堆棧的最下面,放進main記錄。記錄下從哪裡進入的這個函數。
在運行到rfcat(5)這行時,進入這個rfcat函數。此時,n==5。系統棧里,壓入rfcat記錄。
然後在函數里,運行到ans=n*rfact(n-1)時,又遇到了rfcat這個函數,此時,將n-1帶入了這個函數,「遞歸」調用函數。此時,又在系統棧里壓入了一個rfcat記錄。
就這樣重復重復,直到發現出口。就是在n==0時,return了一個值,1。這時,這里的return,不僅是代表返回值,更是說在系統棧里的函數結束了,要返回上一個函數里運行。彈出這個記錄的同時,得到了進入函數時程序的下一步該進行的動作。
然後就這樣一步步的return。直到main的最後的return 0;結束整個程序。
⑧ C語言中,函數的遞歸是如何執行的
{ printf("Move %c to %c\n",source, destination); } <-------從原柱移向目的柱 else <--------如果不是一個盤了,而最後一個盤是最大的,應先到目的柱上 { /* 將最大盤上面的所有盤子遞歸移向helpMedia, 過程是藉助destination,完成後就剩下最大和空的dst柱 PlayHanio(dishNum-1, source, helpMedia, destination); printf("Move %c to %c\n", source, destination); <---經過上面最大盤就能移向空的destination /* 最後,把上面移在helpMedia的盤子按該方法都移向destination,注意最大盤子和盤子個數現在變了哦*/ PlayHanio(dishNum-1, helpMedia, destination, source);}}int main(void){char first='A', second='B', third='C'; <---------三條柱A,B,C int dishNum = 3; <-------盤子個數假設三個 PlayHanio(dishNum, first, second, third); return 0; }。。上面是漢諾塔的原理,如果你記住了這,編出該程序很容易建議試從3,4個盤子去進行程序分析,因為原理是一樣,只是那些柱在遞歸時是不斷變化的,這要注意!!但是多個就不太現實了,假設有N個盤子,那你就移動2^n-1次哦。學遞歸建議開始記住它的原理,能編出程序就可以,不要老是想追根究底,這樣你總是連程序都不會編如快速排序,二叉樹……當然上述對我是可以的,對你我就不清楚了,自己去嘗出一條路吧。。還有就是遞歸的原理其實是涉及到堆棧的壓棧和出棧的,也不難啦,它不能提高速度,相反,每遞歸一次,它就得把上一個函數的地址壓棧,這樣遞歸次數多時內存就大啊但是,但的一大作用就是讓程序清晰明了!
⑨ C語言什麼是遞歸
遞歸方法的概念
類方法成員間允許相互調用,也可以自己調用自己。類的方法如果在方法體內直接或間接地自己調用自己就稱為遞歸方法。
遞歸基本思想就是「自己調用自己」。遞歸方法實際上體現了「依此類推」、「用同樣的步驟重復」這樣的思想,它可以用簡單的程序來解決某些復雜的計算問題。
遞歸調用在完成階乘運算、級數運算、冪指數運算等方面特別有效。
在執行遞歸操作時,C#語言把遞歸過程中的信息保存在堆棧中。如果無限循環地遞歸,或者遞歸次數太多,則產生「堆棧溢出」錯誤
例:用遞歸方法求階乘。利用的數學公式為n!=n*(n-1)!。當n=0時,n!=1。
代碼如下:
public long F(int n)
{
if (n==1)
return 1;
else
return n*F(n-1);
}