函數與程序結構_第1頁
函數與程序結構_第2頁
函數與程序結構_第3頁
函數與程序結構_第4頁
函數與程序結構_第5頁
已閱讀5頁,還剩104頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第5章函數與程序結構(A)主要內容引用類型(5.6)函數創(chuàng)建(5.2)函數調用(5.3)函數原型(5.8)內聯(lián)函數(5.16)重載函數(5.7)默認參數的函數(5.9)函數的嵌套調用函數的遞歸調用(8.1-8.4,8.6-8.7)小結與作業(yè)2課件制作5.1引用類型引用是一種新的變量類型,它的作用是為一個變量起一個別名,是C++對C的一個重要擴充引用運算符&引用語法格式:目標類型&引用名字;引用作為目標的別名而使用,對引用的改動就是對目標的改動引用只有聲明,沒有定義inta;//定義a是整型變量int&b=a;//聲明b是a的引用以上語句聲明了b是a的引用,即b是a的別名3課件制作5.1引用類型引用在聲明時必須被初始化,即聲明它代表哪一個變量,否則產生編譯錯誤聲明變量b為引用類型,并不需要另外開辟內存單元來存放b的值;b和a占內存中的同一個存儲單元,它們具有同一地址;聲明b是a的引用,可以理解為:使變量b具有變量a的地址4課件制作5.1引用類型//引用和變量的關系。#include<iostream>#include<iomanip>usingnamespacestd;intmain(){

inta=10;

int&b=a;//聲明b是a的引用

a=a*a;//a的值變化了,b的值也應一起變化

cout<<a<<setw(6)<<b<<endl;b=b/5;//b的值變化了,a的值也應一起變化

cout<<b<<setw(6)<<a<<endl;return0;}運行記錄如下:

100 100(a和b的值都是100)20 20(a和b的值都是20)5課件制作5.1引用類型#include<iostream>usingnamespacestd;intmain(){

int

intOne;

int&rInt=intOne;

intOne=5;

cout<<"intOne:"<<intOne<<endl;

cout<<"rInt:"<<rInt<<endl;

cout<<"&intOne:"<<&intOne<<endl;

cout<<"&rInt:"<<&rInt<<endl<<endl;

int

intTwo=8;

rInt=intTwo;//將intTwo的值賦值給rInt

cout<<"rInt:"<<rInt<<endl;

cout<<"intOne:"<<intOne<<endl;

cout<<"intTwo:"<<intTwo<<endl<<endl;

cout<<"&intOne:"<<&intOne<<endl;

cout<<"&intTwo:"<<&intTwo<<endl;

cout<<"&rInt:"<<&rInt<<endl;return0;}6課件制作5.1引用類型引用的限制若一個變量聲明為T類型的引用時,它必須用T類型的變量或對象,或能夠轉換為T類型的對象進行初始化若引用類型T的初始值不是一個左值,則將建立一個T類型的目標并用初始值初始化,那個目標的地址變成引用的地址不允許對void類型進行引用double&rDl=1;doubletmp;tmp=double(1);double&rDl=tmp;7課件制作5.2函數創(chuàng)建一個函數就是一個語句的集合,這些語句組合在一起完成一項操作C++程序就是由一些列函數組成,這些函數分為系統(tǒng)函數和自定義函數函數語法形式returnValueType

functionName(listofparameters){//Functionbody}8課件制作5.2函數創(chuàng)建int

fnMax(intnum1,intnum2){

intresult;if(num1>num2)result=num1;elseresult=num2;returnresult;}函數頭函數體返回值類型函數名形式參數參數列表返回值#include<iostream>usingnamespacestd;intmain(){

intret;

intn1=8,n2=9;

ret=fnMax(n1,n2);

cout<<"Themaxof"<<n1<<"and"<<n2<<"is"<<ret<<endl;return0;}函數調用實際參數9課件制作5.2函數創(chuàng)建函數頭指明了返回值類型、函數名和函數參數一個函數可以返回一個值,也可以只執(zhí)行指定的操作而不返回值有返回值的函數必須用returnValueType指定函數返回值的數據類型,該類函數稱為返回值函數無返回值的函數返回值類型部分應使用關鍵字void,該類函數稱為void函數函數頭中定義的變量稱為形式參數,簡稱形參。被傳遞的值稱為實際參數,簡稱實參參數列表指明了函數的參數類型、次序和數量參數是可選的,即一個函數可以沒有參數函數體包含一個語句集合,定義了函數做什么10課件制作5.2函數創(chuàng)建創(chuàng)建無參函數定義無參函數的一般形式為類型標識符

函數名([void]){

聲明部分;語句;

}類型標識符用來指定函數的類型,即函數帶回來的值的類型。//定義fnPrintMessage函數void

fnPrintMessage(void){

cout<<"WelcometoC++!"<<endl;//輸出一行文字}11課件制作5.2函數創(chuàng)建創(chuàng)建有參函數定義有參函數的一般形式為:類型標識符

函數名(形式參數列表){

聲明部分;

語句;}//函數首部,函數值為整型,有兩個整型形參int

fnMax(intx,inty){

intz;//函數體中的聲明部分

z=x>y?x:y;//將x和y中的大者的值賦給整型變量zreturn(z);//將z的值作為函數值返回調用點}C++要求在定義函數時必須指定函數的類型。12課件制作5.2函數創(chuàng)建函數返回值返回值應屬于某一個確定的類型,在定義函數時必須指定函數返回值的類型函數的返回值有兩種類型:void

類型函數(無返回值)可以有return,也可以不寫return語句,函數體的右花括號有返回的功能return;只返回程序執(zhí)行的控制權有返回值:return(表達式);

return具有返回值類型的變量或常量;return語句后面的括號可以要,也可以不要:return(x);或returnx;return后面的值也可以是一個表達式,如returnx+y-fabs(c);函數中可以有多個return語句,大多出現在if語句中,但只能返回一個值13課件制作5.2函數創(chuàng)建函數返回值如果函數值的類型和return語句中表達式的值不一致,則以函數類型為準,即函數類型決定返回值的類型;對數值型數據,可以自動進行類型轉換函數的返回值是通過函數中的return語句獲得的,return語句將被調用函數中的一個確定值帶回主調函數中去14課件制作5.3函數調用函數調用的方式函數語句把函數調用單獨作為一個語句,并不要求函數帶回一個值,只是要求函數完成一定的操作,如fnPrintMessage();函數表達式函數出現在一個表達式中,這時要求函數帶回一個確定的值以參加表達式的運算,如c=2*fnMax(a,b);函數參數函數調用作為一個函數的實參,如

m=fnMax(a,fnMax(b,c));

fnMax(b,c)是函數調用,其值作為外層fnMax

函數調用的一個實參15課件制作5.3函數調用#include<iostream>usingnamespacestd;//求兩個數的極值int

fnMax(intnum1,intnum2){

intresult;if(num1>num2)result=num1;elseresult=num2;returnresult;}//定義fnPrintMessage函數void

fnPrintMessage(){

//輸出一行文字

cout<<"WelcometoC++!"<<endl;}intmain(){//函數調用

fnPrintMessage();

intret;

intn1=8,n2=9,n3=10,n4=5;

//函數調用

ret=fnMax(n1,n2);

cout<<"Themaxof"<<n1<<"and"<<n2<<"is"<<ret<<endl;//函數調用

ret=fnMax(n1,fnMax(n3,n4));

cout<<"Themaxof"<<n1<<","<n3<<"and"<<n3<<"is"<<ret<<endl;return0;}16課件制作5.3函數調用函數調用的執(zhí)行當一個程序調用一個函數時,程序控制流轉向到被調用的函數當被調用函數的return語句執(zhí)行之后或者當到達函數結尾大括號時,它將控制權交還給調用者main()調fun()結束fun()返回①②④⑥⑦保存:返回地址當前現場③恢復:主調程序現場返回地址⑤17課件制作5.3函數調用18課件制作iisnow5函數調用執(zhí)行過程5.3函數調用19課件制作jisnow2函數調用執(zhí)行過程5.3函數調用20課件制作invokemax(i,j)5.3函數調用函數調用執(zhí)行過程21課件制作invokemax(i,j)Passthevalueofitonum1Passthevalueofjtonum25.3函數調用函數調用執(zhí)行過程22課件制作declarevariableresult5.3函數調用函數調用執(zhí)行過程23課件制作(num1>num2)istruesincenum1is5andnum2is25.3函數調用函數調用執(zhí)行過程24課件制作resultisnow55.3函數調用函數調用執(zhí)行過程25課件制作returnresult,whichis55.3函數調用函數調用執(zhí)行過程26課件制作returnmax(i,j)andassignthereturnvaluetok5.3函數調用函數調用執(zhí)行過程27課件制作Executetheprintstatement5.3函數調用函數調用執(zhí)行過程28課件制作函數調用堆棧變化5.3函數調用29課件制作iisdeclaredandinitialized5.3函數調用30課件制作jisdeclaredandinitialized5.3函數調用31課件制作Declarek5.3函數調用32課件制作Invokemax(i,j)5.3函數調用33課件制作passthevaluesofiandjtonum1andnum25.3函數調用34課件制作(num1>num2)istrue5.3函數調用35課件制作Assignnum1toresult5.3函數調用36課件制作Returnresultandassignittok5.3函數調用37課件制作Executeprintstatement5.3函數調用38課件制作5.3函數調用函數調用時的參數要求如果是調用無參函數,則“實參表列”可以沒有,但括號不能省略實參與形參的個數應相等,類型應匹配(相同或賦值兼容)如果實參表列包含多個實參,則各參數間用逗號隔開實參與形參按順序對應,一對一地傳遞數據39課件制作5.3函數調用#include<iostream>usingnamespacestd;//定義fnMax函數int

fnMax(intnum1,intnum2){

intresult;if(num1>num2)result=num1;elseresult=num2;returnresult;}//定義fnPrintMessage函數voidfnPrintMessage(){

cout<<"WelcometoC++!"<<endl;//輸出一行文字}intmain(){

//調用無參、無返回值函數

fnPrintMessage();

intret;

intn1=8,n2=9;

//調用有參、有返回值函數

ret=fnMax(n1,n2);

cout<<"Themaxof"<<n1<<"and"<<n2<<"is"<<ret<<endl;return0;}40課件制作5.3函數調用函數調用時形參與實參的關系在定義函數時,必須在函數首部指定形參的類型在定義函數時指定的形參,在未進行函數調用時并不占內存中的存儲單元;在發(fā)生函數調用時,函數max中的形參會被分配內存單元,以便接收從實參傳來的數據;在調用結束后,形參所占的內存單元自動被釋放實參單元與形參內存單元是不同的單元;調用結束后,形參單元被釋放,實參單元仍保留并維持原值41課件制作5.3函數調用函數調用時形參與實參的關系實參與形參的類型應相同或賦值兼容,如果實參類型與形參類型不同,則按不同類型數值的賦值規(guī)則進行轉換實參可以是常量、變量或表達式,如max(3,a+b),但要求a和b有確定的值,以便在調用函數時將實參的值賦給形參實參變量對形參變量的數據傳遞是“值傳遞”,即單向傳遞,只由實參傳給形參,而不能由形參傳回來給實參42課件制作5.3函數調用函數調用時參數的處理按值方式傳遞參數實參的值復制給形參無論函數中形參的值如何改變,參數變量的值都不會受影響#include<iostream>usingnamespacestd;voidincrement(intn){n++;

cout<<"ninsidethefunctionis"<<n<<endl;}intmain(){

intx=1;

cout<<"Beforethecall,xis"<<x<<endl;

increment(x);

cout<<"afterthecall,xis"<<x<<endl;return0;}43課件制作5.3函數調用#include<iostream>usingnamespacestd;/**Swaptwovariables*/voidswap(intn1,intn2){

cout<<"\tInsidetheswapfunction"<<endl;

cout<<"\t\tBeforeswappingn1is"<<n1<<",n2is"<<n2<<endl;//Swapn1withn2

inttemp=n1;n1=n2;n2=temp;

cout<<"\t\tAfterswappingn1is"<<n1<<",n2is"<<n2<<endl;}44課件制作5.3函數調用intmain(){//Declareandinitializevariables

intnum1=1;

intnum2=2;

cout<<"Beforeinvokingtheswapfunction,num1is"<<num1<<"andnum2is"<<num2<<endl;//Invoketheswapfunctiontoattempttoswaptwovariablesswap(num1,num2);

cout<<"Afterinvokingtheswapfunction,num1is"<<num1<<"andnum2is"<<num2<<endl;return0;}45課件制作5.3函數調用函數調用時參數的處理按引用方式傳遞參數將函數的形參聲明為引用變量形式,調用時傳遞一個常規(guī)變量當改變引用變量(形參)的值時,原變量的值也會改變按引用方式傳遞參數時,形參和實參的類型必須相同;否則有些編譯器產生語法錯誤,有些進行的是值傳遞46課件制作5.3函數調用/**Swaptwovariables*/voidswap(int&n1,int&n2){

cout<<"\tInsidetheswapfunction"<<endl;

cout<<"\t\tBeforeswappingn1is"<<n1<<"n2is"<<n2<<endl;//Swapn1withn2

inttemp=n1;n1=n2;n2=temp;

cout<<"\t\tAfterswappingn1is"<<n1<<"n2is"<<n2<<endl;}47課件制作5.3函數調用#include<iostream>usingnamespacestd;voidfn(double&p){p++;}intmain(){doublef=1;

inti=1;

fn(f);

fn(i);//cannotconvertparameter1from'int'to'double&‘fn(1.0);//cannotconvertparameter1from'constdouble'to'double&'

cout<<"fis"<<f<<endl;

cout<<"iis"<<i<<endl;

return0;}按引用方式傳遞參數時,形參和實參的類型必須相同;否則有些編譯器產生語法錯誤,有些進行的是值傳遞48課件制作5.4函數原型在調用一個函數之前,必須在程序中聲明它將函數創(chuàng)建放在所有函數調用之前在函數調用之前聲明一個函數原型一個函數原型就是一個沒有函數實現(函數體)的單純的函數頭,函數的實現在后續(xù)的程序中給出如果使用用戶自己定義函數,而該函數與調用它的函數(即主調函數)在同一個程序單位中,且位置如果在主調函數之后,則必須在調用此函數之前對被調用的函數作聲明,即函數原型49課件制作5.4函數原型//定義fnMax函數int

fnMax(intnum1,intnum2){

intresult;if(num1>num2)result=num1;elseresult=num2;returnresult;}//定義fnPrintMessage函數voidfnPrintMessage(){//輸出一行文字

cout<<"WelcometoC++!"<<endl;}#include<iostream>usingnamespacestd;//函數原型聲明voidfnPrintMessage();int

fnMax(intnum1,intnum2);intmain(){//調用無參、無返回值函數

fnPrintMessage();

intret;

intn1=8,n2=9;//調用有參、有返回值函數

ret=fnMax(n1,n2);

cout<<"Themaxof"<<n1<<"and"<<n2<<"is"<<ret<<endl;return0;}50課件制作5.4函數原型函數原型的一般形式為函數類型函數名(參數類型1參數名1,參數類型2參數名2…);函數類型函數名(參數類型1,參數類型2…);應當保證函數原型與函數首部寫法上的一致,即函數類型、函數名、參數個數、參數類型和參數順序必須相同在函數調用時函數名、實參類型和實參個數應與函數原型一致在函數聲明中可以不寫形參名,而只寫形參的類型,如

int

fnGetMax(int,int);51課件制作5.4函數原型例:對被調用的函數作聲明#include<iostream>usingnamespacestd;intmain(){

floatadd(floatx,floaty);//對add函數作聲明

floata,b,c;

cout<<"pleaseentera,b:";

cin>>a>>b;c=add(a,b);

cout<<"sum="<<c<<endl;return0;}//定義add函數floatadd(floatx,floaty){floatz;

z=x+y;return(z);}//運行情況如下:pleaseentera,b:123.68456.45↙sum=580.13在函數聲明中,函數原型也可以不寫形參名,而只寫形參的類型floatadd(float,float);52課件制作5.4函數原型

下列函數原型聲明哪些是否正確?錯誤的錯在何處?

int

add(intx,inty);

int

add(intx,inty)

int

add(int

x,y);

int

add(intx;inty);正確錯誤:缺少;錯誤:形參y缺少類型

錯誤:形參x,y之間應為,

53課件制作5.5內聯(lián)函數函數調用時需要一定的時間和空間的開銷內聯(lián)函數:C++提供的一種提高程序執(zhí)行效率的方法,即在編譯時將所調用函數的代碼直接嵌入到主調函數中,而不是將流程轉出去,這種嵌入到主調函數中的函數稱為內聯(lián)函數(inlinefunction),又稱內嵌函數,在有些書中把它譯成內置函數54課件制作5.5內聯(lián)函數指定內聯(lián)函數的方法:在函數首行的左端加關鍵字inlineinline

int

max(int,int,int);//聲明函數,注意左端有inline#include<iostream>usingnamespacestd;//聲明函數,注意左端有inlineinlineint

fnMax(int,int,int);intmain(){

inti=10,j=20,k=30,m;m=fnMax(i,j,k);

cout<<"max="<<m<<endl;return0;}//定義max為內聯(lián)函數//求a,b,c中的最大者inlineint

fnMax(inta,int

b,intc){

intmax=a;if(b>max)max=b;if(c>max)max=c;returnmax;}#include<iostream>usingnamespacestd;intmain(){

inti=10,j=20,k=30,m;

m=i;if(j>max)m=j;if(k>max)m=k;

cout<<"max="<<m<<endl;return0;}在編譯時將所調用函數的代碼直接嵌入到主調函數中,而不是將流程轉出去55課件制作5.5內聯(lián)函數使用內聯(lián)函數可以節(jié)省運行時間,但卻增加了目標程序的長度,一般只將規(guī)模很小(一般為5個語句以下)而使用頻繁的函數(如定時采集數據的函數)聲明為內聯(lián)函數內聯(lián)函數中不能包括復雜的控制語句,如循環(huán)語句和switch語句對函數作inline聲明,只是程序設計者對編譯系統(tǒng)提出的一個建議,也就是說它是建議性的,而不是指令性的,編譯系統(tǒng)會根據具體情況決定是否這樣做歸納起來,只有那些規(guī)模較小而又被頻繁調用的簡單函數,才適合于聲明為inline函數。56課件制作5.6函數重載用同一函數名定義參數個數和參數類型不同多個函數稱為函數的重載(functionoverloading),即對一個函數名重新賦予它新的含義,使一個函數名可以多用函數重載的原因:使程序更為清晰易讀,完成相近任務的函數應該設定為相同的名字int

fnMax

(inta,intb,intc);//求3個整數中的最大者floatfnMax(floata,floatb,floatc);//求3個單精度數中最大者int

fnMax(inta,intb);//求2個整數中的最大者int

fnMaxInt(int

a,intb,intc);//求3個整數中的最大者floatfnMaxFloat

(floata,floatb,floatc);//求3個單精度數中最大者int

fnMaxInt2(inta,intb);//求2個整數中的最大者57課件制作5.6函數重載#include<iostream>usingnamespacestd;/**Returnthemaxbetweentwointvalues*/int

max(intnum1,intnum2){if(num1>num2)returnnum1;elsereturnnum2;}/**Findthemaxbetweentwodoublevalues*/doublemax(doublenum1,doublenum2){if(num1>num2)returnnum1;elsereturnnum2;}58課件制作5.6函數重載/**Returnthemaxamongthreedoublevalues*/doublemax(doublenum1,doublenum2,doublenum3){returnmax(max(num1,num2),num3);}intmain(){//Invokethemaxfunctionwithintparameters

cout<<"Themaximumbetween3and4is"<<max(3,4)<<endl;//Invokethemaxfunctionwiththedoubleparameters

cout<<"Themaximumbetween3.0and5.4is"<<max(3.0,5.4)<<endl;//Invokethemaxfunctionwiththreedoubleparameters

cout<<"Themaximumbetween3.0,5.4,and10.14is"<<max(3.0,5.4,10.14)<<endl;return0;}59課件制作5.6函數重載函數重載的要求重載函數的參數個數、參數類型或參數順序三者中必須至少有一種不同,函數返回值類型可以相同也可以不同重載函數的參數個數不同重載函數參數類型不同重載函數參數順序不同返回值類型不同不是函數重載的依據在使用重載函數時,同名函數的功能應當相同或相近,不要用同一函數名去實現完全不相干的功能,可讀性不好,容意誤解60課件制作5.6函數重載重載函數的調用規(guī)則對一個實際的函數調用,首先尋找一個參數完全匹配的函數,若找到就調用它其次,試低一級的對函數的重載方法,例如通過類型轉換可產生參數匹配等,若找到就調用它函數重載的二義性對一個函數調用可能有兩個或更多的與之匹配的函數定義,編譯器無法確定哪個匹配更為精確二義調用會產生編譯錯誤max(2,2.5);←doublemax(doublenum1,doublenum2);61課件制作5.6函數重載#include<iostream>usingnamespacestd;doublemaxNum(intnum1,doublenum2){if(num1>num2)returnnum1;elsereturnnum2;}doublemaxNum(doublenum1,intnum2){if(num1>num2)returnnum1;elsereturnnum2;}intmain(){

cout<<maxNum(1,2)<<endl;return0;}我該調用哪個函數呢?62課件制作5.7默認參數的函數一般情況下,在函數調用時形參從實參那里取得值,實參的個數應與形參相同多次用同樣的實參調用同一函數時,C++支持給形參一個默認值而不必每次再從實參取值,該方法比較靈活,可以簡化編程,提高運行效率floatfnGetArea(floatr=6.5);//函數聲明調用時則可以不必給出實參的值,如:fnGetArea();//相當于fnGetArea(6.5);如果不想使形參取此默認值,則可以通過實參另行給出,如:fnGetArea(7.5);//形參得到的值為7.5,而不是6.563課件制作5.7默認參數的函數求如下級數的部分和,精度為#include<iostream>#include<cmath>usingnamespacestd;doubles(doublex,doubleeps=1e-6){

intn=1;doubles=0.0,t=1.0;while(fabs(t)>=eps){s=s+t;t=t*x/n;n++;}returns;}intmain(){

cout<<"s1="<<s(2.0)<<endl;

cout<<"s2="<<s(3.0)<<endl;

cout<<"s3="<<s(1.0,1e-5)<<endl;return0;}參數eps取1e-5參數eps取默認值1e-664課件制作5.7默認參數的函數如果有多個形參,可以使每個形參有一個默認值,也可以只對一部分形參指定默認值,另一部分形參不指定默認值實參與形參的結合是從左至右順序進行的,指定默認值的參數必須放在形參表列中的最右端,否則出錯voidf1(floata,intc,intb=0,chard='a');//正確voidf2(floata,intb=0,intc,chard='a');//錯誤如果調用上面的f1函數,可以采取下面的形式:f1(3.5,5,3,'x')//形參的值全部從實參得到f1(3.5,5,3)//最后一個形參的值取默認值'a'f1(3.5,5)//最后兩個形參的值取默認值,b=0,d='a'65課件制作5.7默認參數的函數在調用有默認參數的函數時,實參的個數可以與形參的個數不同,實參未給定的,從形參的默認值得到值在使用帶有默認參數的函數時要注意如果函數的定義在函數調用之前,則應在函數定義中給出默認值;如果函數的定義在函數調用之后,則在函數調用之前需要有函數聲明,此時必須在函數聲明中給出默認值,在函數定義時可以不給出默認值一個函數不能既作為重載函數,又作為有默認參數的函數。當調用函數時如果少寫一個參數,系統(tǒng)無法判定是利用重載函數還是利用默認參數的函數,出現二義性,系統(tǒng)無法執(zhí)行。66課件制作5.8函數的嵌套調用C++可以嵌套調用函數,即在調用一個函數的過程中,又調用另一個函數C++不允許對函數作嵌套定義,即在一個函數中不能完整地包含另一個函數。在一個程序中每一個函數的定義都是互相平行和獨立的67課件制作5.8函數的嵌套調用輸入兩個整數,求平方和#include<iostream>usingnamespacestd;intmain(){

intfun1(intx,inty);

int

a,b;

cin>>a>>b;

cout<<"a、b的平方和:"<<fun1(a,b)<<endl;return0;}intfun1(intx,inty){

intfun2(intm);return(fun2(x)+fun2(y));}intfun2(intm){return(m*m);}//運行結果:

34a、b的平方和:25函數fun1中調用函數fun268課件制作5.9函數的遞歸調用實例:有5個人坐在一起,問第5個人多少歲?他說比第4個人大兩歲;問第4個人歲數,他說比第3個人大兩歲;問第3個人,又說比第2個人大兩歲;問第2個人,說比第1個人大兩歲;最后問第1個人,他說是10歲。請問第5個人多大?每一個人的年齡都比其前1個人的年齡大兩歲。即age(5)=age(4)+2age(4)=age(3)+2age(3)=age(2)+2age(2)=age(1)+2age(1)=10可以用式子表述如下:age(n)=10(n=1)age(n)=age(n-1)+2(n>1)69課件制作5.9函數的遞歸調用可以看到,當n>1時,求第n個人的年齡的公式是相同的,因此可以用一個函數表示上述關系70課件制作5.9函數的遞歸調用在調用一個函數的過程中又出現直接或間接地調用該函數本身,稱為函數的遞歸(recursive)調用,C++允許函數的遞歸調用//求年齡的遞歸函數int

fnAge(intn){

intc;//用c作為存放年齡的變量

if(n==1)//當n=1時,年齡為10c=10;else//當n>1時,此人年齡是他前一個人的年齡加2c=fnAge(n-1)+2;returnc;//將年齡值帶回主函數}71課件制作5.9函數的遞歸調用#include<iostream>usingnamespacestd;int

fnAge(int);//函數聲明intmain()//主函數

{

cout<<fnAge(5)<<endl;return0;}//求年齡的遞歸函數int

fnAge(intn){

intc;//用c作為存放年齡的變量

if(n==1)//當n=1時,年齡為10c=10;else//當n>1時,此人年齡是他前一個人的年齡加2c=fnAge(n-1)+2;returnc;//將年齡值帶回主函數}運行結果如下:18age(5)

age(4)+2

age(3)+2

age(2)+2

age(1)+21072課件制作5.9函數的遞歸調用程序中不應出現無終止的遞歸調用,而只應出現有限次數的、有終止的遞歸調用;通常用if語句來控制,只有在某一條件成立時才繼續(xù)執(zhí)行遞歸調用,否則就不再繼續(xù)73課件制作5.9函數的遞歸調用

CH5:用遞歸方法求n!求n!可以用遞推方法,即從1開始,乘2,再乘3……一直乘到n;也可以用遞歸方法,即5!=5×4!,而4!=4×3!,…,1!=1,可用下面的遞歸公式表示://Returnthefactorialforaspecifiedindexint

factorial(intn){if(n==1)//Basecasereturn1;elsereturnn*factorial(n-1);//Recursivecall}//Returnthefactorialforaspecifiedindexint

factorial(intn){

int

i,fac=1;

for(i=1;i<=n,i++)

fac=fac*i;returnfac;}74課件制作5.9函數的遞歸調用#include<iostream>usingnamespacestd;intmain(){//Prompttheusertoenteraninteger

cout<<"Pleaseenteranon-negativeinteger:";

intn;

cin>>n;//Displayfactorial

cout<<"Factorialof"<<n<<"is"<<factorial(n);return0;}//運行情況如下:pleaseinputaninteger:10↙

10!=362880075課件制作factorial(3)factorial(0)=1;factorial(n)=n*factorial(n-1);ComputingFactorial5.9函數的遞歸調用76課件制作factorial(3)=3*factorial(2)

ComputingFactorialfactorial(0)=1;factorial(n)=n*factorial(n-1);5.9函數的遞歸調用77課件制作factorial(3)=3*factorial(2)=3*(2*factorial(1))5.9函數的遞歸調用factorial(0)=1;factorial(n)=n*factorial(n-1);ComputingFactorial78課件制作factorial(3)=3*factorial(2)=3*(2*factorial(1))=3*(2*(1*factorial(0)))

factorial(0)=1;factorial(n)=n*factorial(n-1);5.9函數的遞歸調用ComputingFactorial79課件制作factorial(3)=3*factorial(2)=3*(2*factorial(1))=3*(2*(1*factorial(0)))=3*(2*(1*1)))

factorial(0)=1;factorial(n)=n*factorial(n-1);5.9函數的遞歸調用ComputingFactorial80課件制作factorial(3)=3*factorial(2)=3*(2*factorial(1))=3*(2*(1*factorial(0)))=3*(2*(1*1)))=3*(2*1)factorial(0)=1;factorial(n)=n*factorial(n-1);5.9函數的遞歸調用ComputingFactorial81課件制作factorial(3)=3*factorial(2)=3*(2*factorial(1))=3*(2*(1*factorial(0)))=3*(2*(1*1)))=3*(2*1)=3*2factorial(0)=1;factorial(n)=n*factorial(n-1);5.9函數的遞歸調用ComputingFactorial82課件制作factorial(3)=3*factorial(2)=3*(2*factorial(1))=3*(2*(1*factorial(0)))=3*(2*(1*1)))=3*(2*1)=3*2=6factorial(0)=1;factorial(n)=n*factorial(n-1);5.9函數的遞歸調用ComputingFactorial83課件制作Executesfactorial(4)TraceRecursivefactorial5.9函數的遞歸調用factorial(4)mainmethodStack84課件制作Executesfactorial(3)TraceRecursivefactorial5.9函數的遞歸調用

factorial(4)

return4*factorial(3)

Step0:executesfactorial(4)

85課件制作5.9函數的遞歸調用TraceRecursivefactorial

Executesfactorial(2)factorial(4)

return4*factorial(3)

return3*factorial(2)

Step0:executesfactorial(4)

Step1:executes

factorial(3)

86課件制作Executesfactorial(1)5.9函數的遞歸調用TraceRecursivefactorial87課件制作Executesfactorial(0)5.9函數的遞歸調用TraceRecursivefactorial88課件制作returns15.9函數的遞歸調用TraceRecursivefactorial89課件制作returnsfactorial(0)5.9函數的遞歸調用TraceRecursivefactorial90課件制作returnsfactorial(1)5.9函數的遞歸調用TraceRecursivefactorial91課件制作returnsfactorial(2)5.9函數的遞歸調用TraceRecursivefactorial92課件制作returnsfactorial(3)5.9函數的遞歸調用TraceRecursivefactorial93課件制作returnsfactorial(4)5.9函數的遞歸調用TraceRecursivefactorial94課件制作factorial(4)StackTrace5.9函數的遞歸調用95課件制作5.9函數的遞歸調用CH5_11漢諾塔問題:傳說索羅門廟里有一個塔臺,臺上有3根標號為A,B,C的用鉆石做成的柱子,在A柱子上放著64個金盤,每一個都比下面的略小一些,把A柱子上的金盤子全部移到C柱上的那一天就是世界末日。移動的條件是:一次只能移動一個金盤,移動過程中大金盤不能放在小金盤上面。廟里的僧人一直在移個不停,因為全部的移動是264-1次,如果每秒移動一次的話需要500億年ABC12396課件制作5.9函數的遞歸調用Hanoi塔問題的規(guī)格化描述有n個盤子,標號分別為1,2,3,…,n;有3個塔,標記為A,B,C任何時候,都不允許較大的盤子放在較小的盤子之上初始時,所有盤子都在A塔上每個步驟只能移動一個盤子,且只能移動某個塔上最上面的盤子97課件制作5.9函數的遞歸調用Hanoi塔問題的解n==1A→Bn>1將上面n-1個盤子執(zhí)行A→C,B作為輔助將最下面n號盤子執(zhí)行A→B將n-1個盤子執(zhí)行C→B,A作為輔助98課件制作5.9函數的遞歸調用#include<iostream>usingnamespacestd;/*ThefunctionforfindingthesolutiontomovendisksfromfromTowertotoTowerwithauxTower*/voidmoveDisks(intn,charfromTower,chartoTower,charauxTower){if(n==1)//Stoppingcondition

cout<<"Movedisk"<<n<<"from"<<fromTower<<"to"<<toTower<<endl;else{

moveDisks(n-1,fromTower,auxTower,toTower);

cout<<"Movedisk"<<n<<"from"<<fromTower<<"to"<<toTower<<endl;

moveDisks(n-1,auxTower,toTower,fromTower);}}99課件制作5.9函數的遞歸調用intmain(){//Readnumberofdisks,n

cout<<"Enternumberofdisks:";

intn;

cin>>n;//Findthesolutionrecursively

cout<<"Themovesare:"<<endl;

moveDisks(n,'A','B','C');return0;}100課件制作5.9函數的遞歸調用101課件制作5.9函數的遞歸調用遞歸函數的特性函數都使用if-els

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論