????????我們在學習些新的函數時,首先我們得理解它是什么?是怎么定義的?然后去了解他的用途,最后我們自己要會用,知道用在什么地方?什么時候用?用的時候要注意些什么?
有一個條理清晰的學習邏輯,會讓我們學習起來事半功倍。
小博在這里帶大家從入門到應用,用通俗易懂的文字講清楚函數遞歸。
一、遞歸是什么
遞歸:簡單點說就是函數自己調用自己。可以理解為“俄羅斯套娃”,將一個大型的復雜的問題層層轉化為和原問題相似的規模較小的子問題來求解,直到不能夠再拆分為止。
凡事物極必反,遞歸也一樣。遞歸必須是有條件的,不能夠無限遞歸下去。
遞:遞推;歸:回歸。你品,你細品。 🤨🤨
二、遞歸舉例
come on !! 直接上例題:
求n!:
1、用數學公式求n!
當我沒有學過遞歸時,我腦子里根本想不到用其他的方法,只能根據數學公式,去解決這個問題。
即n!=n*(n-1)*(n-2)*......*2*1。
//用數學公式求n!
#include <stdio.h>
int main()
{int n = 0;int ret = 1;scanf("%d", &n);for (int i = 1; i <= n; i++){ret *= i;}printf("%d", ret);return 0;
}
2、用遞歸的方法求n!
當我學了遞歸之后,看到這個數學問題是有規律的,即:
//用遞歸方法求n!
#include <stdio.h>
int Fact(int n)
{if (n == 0)return 1;elsereturn n * Fact(n - 1); //繼續調用Fact(),直到n=1為止
}int main()
{int n = 0;scanf("%d", &n);int ret=Fact(n); //調用函數Fact()printf("%d", ret);return 0;
}
3、分析遞歸過程
三、遞歸練習
根據上面的講解,想必大家對遞歸也有了初步的了解,下面我來寫一道例題,大家可以自行練習一下。
例:輸入一個整數m,按照順序打印整數的每一位。
比如:輸入1234? ? ? ? 輸出1 2 3 4
1、小博分析
我們先進行分析,可以用筆寫出分析過程,找出規律,往遞歸上靠。
小博分析:
小博剛開始分析時,發現了該過程的規律,但當小博嘗試寫代碼去解決的時候,卻寫不出對應的代碼,完了卡住了 😥😥,你們是不是也經常這樣!!
事后,小博對自己的行為進行了反思,發現:首先我并沒有捋清楚自己的思路,抱著試一試、感覺會了的態度去寫,結果問題沒有解決,反而還花費了大量的時間,同時心靈還受到極大的挫敗感。所以,我們在寫代碼時,要先有清晰明了的思路之后再去寫。俗話說,磨刀不誤砍柴功呢!
回歸正題:
按照上面小博的分析,發現是倒著打印出來該數字的,如果想正著打印的話,還需再分析
我們發現一個數的最低位是最容易得到的,要想辦法把該數拆開,直到拆成一位就不用再拆了。
2、代碼實現
#include <stdio.h>
void print(int m)
{if (m > 9){print(m / 10);}printf("%d ", m % 10);
}int main()
{int m = 0;scanf("%d", &m);print(m); //用來打印m的每一位return 0;
}
代碼的流程
注意:每次調用print()函數時,就會進入該函數,再進入該函數......每一級的print() 都是來自上一步的,然而每次執行完該函數時,都會留下一個printf("%d",m);未被執行,因此執行結束后,還會一步一步返回回歸到上層去執行該語句。
????????此外,使用遞歸的時候要注意,每次遞歸函數的調用都會開辟屬于自己的棧幀空間,稱為運行時堆棧,直到函數遞歸不再繼續,還是回歸才逐釋放棧幀空間。所以遞歸太深,就會浪費太多的棧幀空間,也可能會造成棧溢出。
????????看完上述內容,是否對遞歸有了更深的理解呢!!然而我們要知道,遞歸很難想到,也不一定是最優解,但是有的地方會簡化代碼,讓問題簡單化。
學習數據結構時,會常用到遞歸。
好了小博今天就將到這里,歡迎大家留言評論!!
這里小博再送給大家我喜歡的一句話:“與鳳凰同飛,必是俊鳥;與虎狼同行,必是猛獸。”
加油!!