遞歸是什麼?
遞歸是什麼意思?
遞歸是一種重要的編程技術。該方法用於讓一個函數從其內部調用其自身。一個示例就是計算階乘。0 的階乘被特別地定義為 1。 更大數的階乘是通過計算 1 * 2 * ...來求得的,每次增加 1,直至達到要計算其階乘的那個數。
下面的段落是用文字定義的計算階乘的一個函數。
“如果這個數小於零,則拒絕接收。如果不是一個整數,則將其向下舍入為相鄰的整數。如果這個數為 0,則其階乘為 1。如果這個數大於 0,則將其與相鄰較小的數的階乘相乘。”
要計算任何大於 0 的數的階乘,至少需要計算一個其他數的階乘。用來實現這個功能的函數就是已經位於其中的函數;該函數在執行當前的這個數之前,必須調用它本身來計算相鄰的較小數的階乘。這就是一個遞歸示例。
遞歸和迭代(循環)是密切相關的 — 能用遞歸處理的算法也都可以採用迭代,反之亦然。確定的算法通常可以用幾種方法實現,您只需選擇最自然貼切的方法,或者您覺得用起來最輕鬆的一種即可。
顯然,這樣有可能會出現問題。可以很容易地創建一個遞歸函數,但該函數不能得到一個確定的結果,並且不能達到一個終點。這樣的遞歸將導致計算機執行一個“無限”循環。下面就是一個示例:在計算階乘的文字描述中遺漏了第一條規則(對負數的處理) ,並試圖計算任何負數的階乘。這將導致失敗,因為按順序計算 -24 的階乘時,首先不得不計算 -25 的階乘;然而這樣又不得不計算 -26 的階乘;如此繼續。很明顯,這樣永遠也不會到達一個終止點。
因此在設計遞歸函數時應特別仔細。如果懷疑其中存在著無限遞歸的可能,則可以讓該函數記錄它調用自身的次數。如果該函數調用自身的次數太多,即使您已決定了它應調用多少次,就自動退出。
下面仍然是階乘函數,這次是用 JScript 代碼編寫的。
// 計算階乘的函數。如果傳遞了
// 無效的數值(例如小於零),
// 將返回 -1,表明發生了錯誤。若數值有效,
// 把數值轉換為最相近的整數,並
// 返回階乘。
function factorial(aNumber) {
aNumber = Math.floor(aNumber); // 如果這個數不是一個整數,則向下舍入。
if (aNumber < 0) { // 如果這個數小於 0,拒絕接收。
return -1;
}
if (aNumber == 0) { // 如果為 0,則其階乘為 1。
return 1;
}
else return (aNumber * factorial(aNumber - 1)); // 否則,遞歸直至完成。
}
什麼是遞歸?遞歸有什麼用?
一個過程或函數在其定義或說明中又直接或間接調用自身的一種方法,它通常把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解,遞歸策略只需少量的程序就可描述出解題過程所需要的多次重複計算,大大地減少了程序的代碼量。遞歸的能力在於用有限的語句來定義對象的無限集合。用遞歸思想寫出的程序往往十分簡潔易懂。 一般來說,遞歸需要有邊界條件、遞歸前進段和遞歸返回段。當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。 注意: (1) 遞歸就是在過程或函數裡調用自身; (2) 在使用遞歸策略時,必須有一個明確的遞歸結束條件,稱為遞歸出口。 遞歸算法一般用於解決三類問題: (1)數據的定義是按遞歸定義的。(Fibonacci函數) (2)問題解法按遞歸算法實現。(回溯) (3)數據的結構形式是按遞歸定義的。(樹的遍歷,圖的搜索) 遞歸的缺點: 遞歸算法解題的運行效率較低。在遞歸調用的過程當中系統為每一層的返回點、局部量等開闢了棧來存儲。遞歸次數過多容易造成棧溢出等。遞歸通俗的講就是一個函數在其代碼中反覆調用自身。你應該知道菲波納契數列,這個數列的定義是f(x)=1?(x=1)f(x)=2?(x=2)f(x)=f(x-1)+f(x-2) (x>2)也就是說從第三項開始的每一項的值都等於是前兩項之和。這在數學中叫遞推數列--高中數學內容。
誰能給我舉個例子解釋下遞歸是什麼意思
首先來看一個例子:有一個Febonacci序列:它的問題是:求這個序列中的第N個數。由於它的函數原形是:f(N)=f(n-1)+f(n-2)這用遞歸很容易就可以寫出代碼來,一點都不費事:int Febc(int n) {if(n<3) return (1);elsereturn (Febc(n-1)+Febc(n-2));}噢~~~~~也許你會說遞歸真是太簡單了,簡直就是一個數學模型嘛,呵呵。其實,遞歸函數的工作過程就是自己調用自己。有一些問題用遞歸就很容易解決,簡單的你自己都會吃驚。我們做事情,一般都是從頭開始的,而遞歸卻是從末尾開始的。比如上面的函數吧,當n>3時,它顯然只能求助於n-1,n-2。而(n-1)>2,(n-2)>2時,它們就求助於:(n-1)-1,(n-1)-2;(n-2)-1,(n-2)-2;然後··············直到(n-k)<3,(n-k-1)<3時,函數Febc終於有了返回值1 了,它再從頭開始計算,然後一直算到n 為止。通過上面的例子,我們知道遞歸一定要有一個停止的條件,否則遞歸就不知道停止了。在上面的例子中, if(n<3) return (1); 就是停止的條件。然而,使用遞歸的代價是十分巨大的:它會消耗大量的內存!!遞歸循環時它用的是堆棧,而堆棧的資源是十分有限的。上面的例子你只能用一個很小的n值。如果n=20,即Febc(20)的話,它將調用Febc(N)函數10000多次!!!而上面一個例子用循環也是十分容易寫的:/*using turboc2*/int febc(int);main(){int n;scanf("%d",&n);febc(N);}int febc(int n){int a[3],i;a[0]=a[1]=a[2]=1;for(i=3;i<=n;i++)a[i%3]=a[(i+1)%3]+a[(i+2)%3]; /*實現 Febc(I)=Febc(i-1)+Febc(i-2)*/printf("\n%d\n",a[n%3]);}有興趣者不妨輸入一個較大的n值,然後比較比較這二個函數計算的速度。當然, 如果你使用的n太大的話,遞歸可能發生錯誤。如果死機了可別罵我哦~~~ 我已經提醒過你了 :)現在我們再來看看一個求從1 加到100的循環:下面就是遞歸(請注意了,這種做法不推薦!! 我只是為了說明問題才這麼寫的。)/*using Turboc2*/int a=0;int account(int);main(){account(100);printf("%d",a);}int account(int i){if(i==1) return 1; /*停止條件*/elsereturn (n+f(n-1)); /*此句有問題*/}在C/C++的問題中,我曾經回答過這樣的一個問題:先寫出函數表達式:f(N)=f(n-1)+f(n-3)f(N)-f(n-1)=f(n-3)因為第n年要比n-1年多的牛,都是大於三歲的牛生的小牛,而f(n-3)正是那些在n年大於三歲的牛,然後它們在第n年生下相同數量的小牛。(請用BorlandC++3.1或其他C++編譯器)#include
什麼是遞歸算法
遞歸算法就是一個函數通過不斷對自己的調用而求得最終結果的一種思維巧妙但是開銷很大的算法。
比如:
漢諾塔的遞歸算法:
void move(char x,char y){
printf("%c-->%c\n",x,y);
}
void hanoi(int n,char one,char two,char three){
/*將n個盤從one座藉助two座,移到three座*/
if(n==1) move(one,three);
else{
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
}
}
main(){
int n;
printf("input the number of diskes:");
scanf("%d",&n);
printf("The step to moving %3d diskes:\n",n);
hanoi(n,'A','B','C');
}
我說下遞歸的理解方法
首先:對於遞歸這一類函數,你不要糾結於他是幹什麼的,只要知道他的一個模糊功能是什麼就行,等於把他想象成一個能實現某項功能的黑盒子,而不去管它的內部操作先,好,我們來看下漢諾塔是怎麼樣解決的
首先按我上面說的把遞歸函數想象成某個功能的黑盒子,void hanoi(int n,char one,char two,char three); 這個遞歸函數的功能是:能將n個由小到大放置的小長方形從one 位置,經過two位置 移動到three位置。那麼你的主程序要解決的問題是要將m個的"漢諾塊"由A藉助B移動到C,根據我們上面說的漢諾塔的功能,我相信傻子也知道在主函數中寫道:hanoi(m,A,B,C)就能實現將m個塊由A藉助B碼放到C,對吧?所以,mian函數裡面有hanoi(m,'A','C','B');這個調用。
接下來我們看看要實現hannoi的這個功能,hannoi函數應該幹些什麼?
在hannoi函數裡有這麼三行
hanoi(n-1,one,three,two);
move(one,three);
hanoi(n-1,two,one,three);
同樣以黑盒子的思想看待他,要想把n個塊由A經過B搬到C去,是不是可以分為上面三步呢?
這三部是:第一步將除了最後最長的那一塊以外的n-1塊由one位置經由three搬到two 也就是從A由C搬到B 然後把最下面最長那一塊用move函數把他從A直接搬到C 完事後 第三步再次將剛剛的n-1塊藉助hanno處函數的功能從B由A搬回到C 這樣的三步實習了n塊由A經過B到C這樣一個功能,同樣你不用糾結於hanoi函數到底如何實現這個功能的,只要知道他有這麼一個神奇的功能就行
最後:遞歸都有收尾的時候對吧,收尾就是當只有一塊的時候漢諾塔怎麼個玩法呢?很簡單吧,直接把那一塊有Amove到C我們就完成了,所以hanoni這個函數最後還要加上 if(n==1)move(one,three);(當只有一塊時,直接有Amove到C位置就行)這麼一個條件就能實現hanoin函數n>=1時......
什麼是遞歸的概念?
1至100的和這個程序需要循環求sum=sum+i(i每次自增1)。沒有用到遞歸,
1至100的和累積求值,遞歸調用是一個循環程序的調用
sum=sum+i只是C語言的一個實現的函數語句!
遞歸的基本概念和特點
程序調用自身的編程技巧稱為遞歸( recursion)。
一個過程或函數在其定義或說明中又直接或間接調用自身的一種方法,它通常把一個大型複雜的問題層層轉化為一個與原問題相似的規模較小的問題來求解,遞歸策略只需少量的程序就可描述出解題過程所需要的多次重複計算,大大地減少了程序的代碼量。遞歸的能力在於用有限的語句來定義對象的無限集合。用遞歸思想寫出的程序往往十分簡潔易懂。
一般來說,遞歸需要有邊界條件、遞歸前進段和遞歸返回段。當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。
注意:
(1) 遞歸就是在過程或函數裡調用自身;
(2) 在使用遞增歸策略時,必須有一個明確的遞歸結束條件,稱為遞歸出口。
參考資料:無 C++
遞歸方法是什麼
我寫了個小遞歸程序你看看能不能給你點啟示:
public static void p(String s, int pos) {
int m = s.length() / 2;
System.out.print("輸出"+Math.abs(m - pos)+"次*___");
for (int i = 0; i俯< Math.abs(m - pos); i++) {
System.out.print("*");
}
System.out.println(s.charAt(pos));//輸出本次的字符
if (pos + 1 < s.length()) {
p(s, pos + 1);
}
}
public static void main(String[] args) {
p("123456789", 0);//調用遞歸方法
}
效果圖:
輸出4次*___****1
輸出3次*___***2
輸出2次*___**3
輸出1次*___*4
輸出0次*___5
輸出1次*___*6
輸出2次*___**7
輸出3次*___***8
輸出4次*___****9
個人感覺:遞歸就在條件允許的前提下在一個方法內自己調自己,從而實現循環的功能
為什麼遞歸是什麼
遞歸就是有遞有歸
簡單來說就是程序或者函數自己調用自己,以此來將問題簡化
直接遞歸,和間接遞歸是什麼
拿函數來說
直接遞歸是在A函數中嵌套使用A函數 然後有一個停止該川數的條件
間接遞歸是在A函數中調用B函數,然後在B函數中調用A函數,實現遞歸
遞歸算法,什麼叫遞歸
/**
* 概念介紹:
* 遞歸是一種方法(函數)調用自已編程技術。
* 遞歸就是程序設計中的數學歸納法。
* 例如:tri(n)=1 if n=1
* tri(n)=n+tri(n-1) if n>1
* 可能while循環方法執行的速度比遞歸方法快,但是為什麼採用遞歸呢。
* 採用遞歸,是因為它從概念上簡化了問題,而不是因為它提高效率。
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Recursion {//求三角數字的遞歸算法:1,3,6,10,15,21, ......
static int theNumber;
public static void main(String[] args) throws IOException {
System.out.print("Enter a number: ");
theNumber = getInt();
//使用遞歸時調用,默認
int theAnswer = triangle(theNumber);
//使用非遞歸時調用
//int theAnswer=triangle2(theNumber);
System.out.println("Result: " + theAnswer);
}
public static int triangle(int n) {//遞歸方法,循環調用
if (n == 1) {
return 1;
} else {
return (n + triangle(n - 1));
}
}
public static int triangle2(int n) {//非遞歸方法
int total = 0;
while (n > 0) {
total = total + n--;
}
return total;
}
public static String getString() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
public static int getInt() throws ......
遞歸有什麼特點?
遞歸函數的特點: 函數定義中直接或間接地調用了本函數,必定存在可使遞歸調用終止的條件,否則導致出現無限遞歸。
函數定義中所具有的這些特點是判斷函數是否為遞歸函數的基本要素。
換言之,能用遞歸解決的問題通駭具有兩個特點:
1 有退出條件
2 外層需要用到內層算出的結果(也可能是內層需要外層的計算結果,但比較少見)
最難的地方是找出外層利用內層結果的方法,這往往需要在思考問題的過程中發現規律,紙筆是不可缺少的。
另外退出條件需要拿捏準確,這也是一個容易出錯的地方。