package cn.dg;
/**
* 哈嘍,大家好!
* 今天講一下Java中的遞歸;
*
* 遞歸
* 所謂的遞歸:就是是自己調用自己;
* 當然我們不能讓自己的程序一直這樣重複下去,因此遞歸使用時一定要注意它的規則邊界;
*
* 遞歸分類:
* 接下來聊一下遞歸常見的表現形式;
* 一般我們對於遞歸的應用無非就兩種情況:
* 1. 自己調用自己;(直接遞歸)
* 2. A,B,N+ 回調 A,B,N+;(間接遞歸)
* 我們稱第一種自己調用自己的這種遞歸方式爲常用的直接遞歸;
* 而第二種大型遞歸方式稱爲間接遞歸;
*
* 規則邊界:
* 1. 構造方法不能遞歸;(構造器是用來創建對象的,因而不能讓這種消耗型動作持續的去創建對象)
* 2. 遞歸運算在設計過程中一定要有作爲出口的終止限定條件;(死循環會造成棧內存溢出)
* 3. 同樣,設計遞歸運算時一定要考慮到遞歸實際佔用內存的問題,要對遞歸的次數添加限定;
* (如果還沒有執行到跳出遞歸的條件約束,JVM內存就用光,也會報棧內存溢出;)
*
* 好,還是和以前一樣;
* 首先創建一個自己的測試類;
* @author TANJIYUAN
*/
public class DgTest {
/**
* 創建一個計算1~n位數字之和的方法;
* 實現:
* 1+2+3+n...
* x+(x+1)|x+(++x); -> 1+(1+1) -> 1+2
* x+(x+1)|x+(++x); -> 2+(2+1) -> 2+3
* x+(x+1)|x+(++x); -> ...
* 在程序中實現可以把第二步2+3的缺值通過補足的方式來彌補;ok;
* 那清晰了思路,實現起來就相對easy;Let's go...
*
*
* 在goon(int num)這個方法中:
* 所實現的方法是限制基數重大大小遞減的方式(當然也可以使用由小到大的方式);實現;
*
* @param num
* @return
*/
public static int goon(Integer num) {
/**
* 首先判斷一種特殊情況:
* 我們的方法設計開始的規則是:計算1以上的相加數之和;
* 那麼也就說如果是1本身,那無需計算;
* 那麼在這裏直接做返回處理即可;
*/
if(num == 1) {
return 1;
}
/**
* 如果用戶輸入的數字是負數或者0;計算沒有多大意義;
* 所以直接將這種情況作爲出口項進行設計;
*/
if(num <= 0) {
return 0;
}
/**
* 如果用戶傳入的參數過大,超出運行內存的大小;
* 在這裏是需要作爲出口項控制一下的;
*/
if(num >= 500) {
return 0;
}
/**
* 這個地方呢要詳細的說一下:
* 如非大牛之輩恐難以直觀;
* 我們通過一開始的設計分析發現;其實每次的數據計算都有一個公式x+(++x);
* 那麼這個公式所缺的無非就是上一次計算的數據;
*
* 這一點我們可以直接通過回調賦值的方式來彌補;(這是我個人對遞歸方式調用的稱謂)
*
* 那麼num-1是什麼呢?
* 此處想了n久,從小打到的設計思路實現代碼會略微繁瑣,故而採用了這種方式;
* 在方法調用的初期,調用者會預傳一個int類型的參數進來,我需要做的無非就是
* 判斷1以外的情況;以及對數據進行計算即可;
* 因此既然是相加之數,從小到大相加也是一個值;從大到小相加也是一個值,(恰巧用戶輸入的就是
* 一個大值)因此,果斷採用的從大到小的方式,每次直接用傳進來的參數計算即可,都不用處理;
* 到這裏,相信各位已經有所瞭解這裏面的運行機制;
*
*
* 最後呢說一下關於這次遞歸的兩個關鍵性要素在哪裏;
* 我們知道:遞歸的設計使用時一定要有規則邊界的,否則必然會陷入死循環中;
* 因此我們這次的設計實現也不例外,那麼下面就來說明一下這其中的規則邊界;
*
* 首先遞歸的設計一定要有出口,那麼我們的一開始的時候處理1和<=0以及>=500這種情況時,就是出口設計;
* 其中的>=500則是根據佔用情況而設計的出口項;
*/
return num + goon(num-1);
}
/**
* 程序的入口|主函數;
* @param args
*/
public static void main(String[] args) {
/**
* 然後在這裏調用;傳入一個int類型的參數5來進行計算;
* 最終得出15的結果;
* 爲了驗證這個結果的正確性,我拿來了公司唯一的一臺認不出牌子的計算器來進行驗證;
* 最終得出...它是正確答案;
* 那麼至此,關於Java中遞歸的一些小細節就算是告一段落了;
*
* 這個例子很多的地方都有引用到,我其實有想用其他的案例來帶過;
* 但是小腦瓜還沒開竅,一時間呢也沒有更加舒心的案例來給大家說明;
* 所以就將就一下以此爲例,來進行我們Java遞歸的案例說明;
*/
System.out.println(goon(5));
}
}
package cn.dg;
/**
* 對了,在這裏再給大家給一個關於階乘計算的Demo;
* 在開始之前大家先了解一下關於階乘的內容;
* 首先什麼是階乘?
* 1. 階乘是基斯頓·卡曼(Christian Kramp,1760~1826)於 1808 年發明的運算符號,是數學術語;
* 2. 一個正整數的階乘(factorial)是所有小於及等於該數的正整數的積,並且0的階乘爲1;
* 3. 自然數n的階乘寫作n!;
* 4. 寫作:n!=1×2×3×...×(n-1)×n;
* 5. 那麼用遞歸實現:0!=1,n!=(n-1)!×n;(其中0!=1就表示0的階乘爲1;)
*
* 好了,清晰了階乘的原理,那下面就給大家列出關於階乘利用遞歸方式實現的Demo;
*
* 首先還是和以前一樣,我們先創建一個自己的測試類;
* @author Administrator
*
*/
public class DgTest {
/**
* 將階乘處理的代碼封裝入一個方法中;
* 進行迭代機制的處理;
* @param num
* @return
*/
public static int goon(Integer num) {
/**
* 那麼還是和之前一樣;要進行出口項的設置;
* 如果參數<0的話沒有計算的必要;因此將其設置爲一項出口項處理;
*/
if(num < 0) {
return 0;
}
/**
* 在設計的時候很容易忘記這塊的設計;
* 我們只顧着遞減了,沒有添加對應的限制,如果成0之後任何數相乘都等於0;
* 因此也要將此項當作一個出口項處理;
*/
if(num == 1) {
return 1;
}
/*
* 好,那到了最後就是我們的計算工作;
* 直接利用我們之前分析好的公式將其帶入即可;
*/
return num * goon(num-1);
}
/**
* 程序入口|主函數;
* @param args
*/
public static void main(String[] args) {
/**
* 在這裏進行封裝好迭代方法的調用;
* 我們還是傳入一個5的參數;
* 還是和之前一樣,我準備了一個陳舊但精準的計算器,進行了結果驗證;
* 最終的結論:它是對的;
*/
System.out.println(goon(5));
}
}
package cn.dg;
import java.io.File;
/**
* 下面再列一個文件獲取的迭代Demo;
*
* 創建一個自己的測試類;
* @author Administrator
*
*/
public class DgTest {
/**
* 封裝對應的迭代機制;
* @param file: 方法需要傳入一個文件對象;
*/
public static void goonFile(File file) {
/**
* 通過文件對象獲取該對象目錄下的所有File目錄對象;
* 以數組形式返回;
*/
File [] listFile = file.listFiles();
/**
* 循環數組;
*/
for(File thisFile : listFile) {
/**
* 出口項;
*
* isFile();
* 判斷是否爲文件;
*/
if(thisFile.isFile()){
/**
* getName();
* 打印文件的文件名;
*
* getAbsolutePath();
* 返回文件的絕對路徑;
*/
System.out.println(thisFile.getName() + ": " + thisFile.getAbsolutePath());
}
/**
* isDirectory();
* 判斷是否爲文件夾;
*/
if(thisFile.isDirectory()) {
goonFile(thisFile);
}
}
}
/**
* 程序入口|主函數;
* @param args
*/
public static void main(String[] args) {
/**
* 初始化一個地址參數;
*/
String path = "D:\\Software\\JDK";
/**
* 實例化文件對象;
* 傳入初始化的地址參數;
*/
File file = new File (path);
/**
* 調用封裝好的方法;
*/
goonFile(file);
}
}