這篇文章主要介紹了C++函數的嵌套調用和遞歸調用學習教程,是C++入門學習中的基礎知識,需要的朋友可以參考下
C++函數的嵌套調用
C++不允許對函數作嵌套定義,也就是說在一個函數中不能完整地包含另一個函數。在一個程序中每一個函數的定義都是互相平行和獨立的。
雖然C++不能嵌套定義函數,但可以嵌套調用函數,也就是說,在調用一個函數的過程中,又調用另一個函數。
在程序中實現函數嵌套調用時,需要注意的是:在調用函數之前,需要對每一個被調用的函數作聲明(除非定義在前,調用在后)。
【例】用弦截法求方程f(x)=x3-5x2+16x-80=0的根。
這是一個數值求解問題,需要先分析用弦截法求根的算法。根據數學知識,可以列出以下的解題步驟:
1) 取兩個不同點x1,x2,如果f(x1)和f(x2)符號相反,則(x1,x2)區間內必有一個根。如果f(x1)與f(x2)同符號,則應改變x1,x2,直到f(x1), f(x2)異號為止。注意x1?x2的值不應差太大,以保證(x1,x2)區間內只有一個根。
2) 連接(x1, f(x1))和(x2, f(x2))兩點,此線(即弦)交x軸于x,見圖。
x點坐標可用下式求出:
再從x求出f(x)。
3) 若f(x)與f(x1)同符號,則根必在(x, x2)區間內,此時將x作為新的x1。如果f(x)與f(x2)同符號,則表示根在( x1,x)區間內,將x作為新的x2。
4) 重復步驟 (2) 和 (3), 直到 |f(x)|<ξ為止, ξ為一個很小的正數, 例如10-6。此時認為 f(x)≈0。
這就是弦截法的算法,在程序中分別用以下幾個函數來實現以上有關部分功能:
1) 用函數f(x)代表x的函數:x3-5x2+16x-80。
2) 用函數xpoint (x1,x2)來求(x1,f(x1))和(x2,f(x2))的連線與x軸的交點x的坐標。
3) 用函數root(x1,x2)來求(x1,x2)區間的那個實根。顯然,執行root函數的過程中要用到xpoint函數,而執行xpoint函數的過程中要用到f函數。
根據以上算法,可以編寫出下面的程序:
- #include <iostream>
- #include <iomanip>
- #include <cmath>
- using namespace std;
- double f(double); //函數聲明
- double xpoint(double, double); //函數聲明
- double root(double, double); //函數聲明
- int main( )
- {
- double x1,x2,f1,f2,x;
- do
- {
- cout<<"input x1,x2:";
- cin>>x1>>x2;
- f1=f(x1);
- f2=f(x2);
- } while(f1*f2>=0);
- x=root(x1,x2);
- cout<<setiosflags(ios::fixed)<<setprecision(7);
- //指定輸出7位小數
- cout<<"A root of equation is "<<x<<endl;
- return 0;
- }
- double f(double x) //定義f函數,以實現f(x)
- {
- double y;
- y=x*x*x-5*x*x+16*x-80;
- return y;
- }
- double xpoint(double x1, double x2) //定義xpoint函數,求出弦與x軸交點
- {
- double y;
- y=(x1*f(x2)-x2*f(x1))/(f(x2)-f(x1)); //在xpoint函數中調用f函數
- return y;
- }
- double root(double x1, double x2) //定義root函數,求近似根
- {
- double x,y,y1;
- y1=f(x1);
- do
- {
- x=xpoint(x1,x2); //在root函數中調用xpoint函數
- y=f(x); //在root函數中調用f函數
- if (y*y1>0)
- {
- y1=y;
- x1=x;
- }
- else
- x2=x;
- }while(fabs(y)>=0.00001);
- return x;
- }
運行情況如下:
- input x1, x2:2.5 6.7↙
- A root of equation is 5.0000000
對程序的說明:
1) 在定義函數時,函數名為f,xpoint和root的3個函數是互相獨立的,并不互相從屬。這3個函數均定為雙精度型。
2) 3個函數的定義均出現在main函數之后,因此在main函數的前面對這3個函數作聲明。
習慣上把本程序中用到的所有函數集中放在最前面聲明。
3) 程序從main函數開始執行。
4) 在root函數中要用到求絕對值的函數fabs,它是對雙精度數求絕對值的系統函數。它屬于數學函數庫,故在文件開頭用#include
C++函數的遞歸調用
在調用一個函數的過程中又出現直接或間接地調用該函數本身,稱為函數的遞歸(recursive)調用。C++允許函數的遞歸調用。例如:
- int f(int x)
- {
- int y, z;
- z=f(y); //在調用函數f的過程中,又要調用f函數
- return (2*z);
- }
以上是直接調用本函數,見下面的圖。
下圖表示的是間接調用本函數。在調用f1函數過程中要調用f2函數,而在調用f2函數過程中又要調用f1函數。
從圖上可以看到,這兩種遞歸調用都是無終止的自身調用。顯然,程序中不應出現這種無終止的遞歸調用,而只應出現有限次數的、有終止的遞歸調用,這可以用if語句來控制,只有在某一條件成立時才繼續執行遞歸調用,否則就不再繼續。
包含遞歸調用的函數稱為遞歸函數。
【例】有5個人坐在一起,問第5個人多少歲?他說比第4個人大兩歲。問第4個人歲數,他說比第3個人大兩歲。問第3個人,又說比第2個人大兩歲。問第2個人,說比第1個人大兩歲。最后問第1個人,他說是10歲。請問第5個人多大?
每一個人的年齡都比其前1個人的年齡大兩歲。即:
- age(5)=age(4)+2
- age(4)=age(3)+2
- age(3)=age(2)+2
- age(2)=age(1)+2
- age(1)=10
可以用式子表述如下:
- age(n)=10 (n=1)
- age(n)=age(n-1)+2 (n>1)
可以看到,當n>1時,求第n個人的年齡的公式是相同的。因此可以用一個函數表示上述關系。圖4.11表示求第5個人年齡的過程。
可以寫出以下C++程序,其中的age函數用來實現上述遞歸過程。
- #include <iostream>
- using namespace std;
- int age(int);//函數聲明
- int main( )//主函數
- {
- cout<<age(5)<<endl;
- return 0;
- }
- int age(int n)//求年齡的遞歸函數
- {
- int c; //用c作為存放年齡的變量
- if(n==1) c=10; //當n=1時,年齡為10
- else c=age(n-1)+2; //當n>1時,此人年齡是他前一個人的年齡加2
- return c; //將年齡值帶回主函數
- }
運行結果如下:
【例】用遞歸方法求n!。
求n!可以用遞推方法,即從1開始,乘2,再乘3……一直乘到n。求n!也可以用遞歸方法,即5!=4!×5,而4!=3!×4,…,1!=1??捎孟旅娴倪f歸公式表示:
- n! = 1 (n=0, 1)
- n * (n-1)! (n>1)
有了例4.10的基礎,很容易寫出本題的程序:
- #include <iostream>
- using namespace std;
- long fac(int);//函數聲明
- int main( )
- {
- int n;//n為需要求階乘的整數
- long y; //y為存放n!的變量
- cout<<"please input an integer :"; //輸入的提示
- cin>>n; //輸入n
- y=fac(n);//調用fac函數以求n!
- cout<<n<<"!="<<y<<endl; //輸出n!的值
- return 0;
- }
- long fac(int n) //遞歸函數
- {
- long f;
- if(n<0)
- {
- cout<<"n<0,data error!"<<endl; //如果輸入負數,報錯并以-1作為返回值
- f=-1;
- }
- else if (n==0||n==1) f=1; //0!和1!的值為1
- else f=fac(n-1)*n;//n>1時,進行遞歸調用
- return f;//將f的值作為函數值返回
- }
運行情況如下:
- please input an integer:10↙
- 10!=3628800
許多問題既可以用遞歸方法來處理,也可以用非遞歸方法來處理。在實現遞歸時,在時間和空間上的開銷比較大,但符合人們的思路,程序容易理解。
新聞熱點
疑難解答