遞迴演算法案例分析
阿新 • • 發佈:2019-01-07
一、遞迴練習(斐波那契數列)
- 不死神兔
- 故事得從西元1202年說起,話說有一位義大利青年,名叫斐波那契。
- 在他的一部著作中提出了一個有趣的問題:假設一對剛出生的小兔一個月後就能長成大兔,再過一個月就能生下一對小兔,並且此後每個月都生一對小兔,一年內沒有發生死亡,
- 問:一對剛出生的兔子,一年內繁殖成多少對兔子?
- 1 1 2 3 5 8 13
- 第一個月一對小兔子 1
- 第二個月一對大兔子 1
- 第三個月一對大兔子生了一對小兔子 2
- 第四個月一對大兔子生了一對小兔子
- 一對小兔子長成大兔子 3
- 第五個月兩對大兔子生兩對小兔子
- 一對小兔子長成大兔子 5
我們首先可以用非遞迴的方法來做這個題目
private static void demo1() { // 方法一 // 用陣列做不死神兔 int[] arr = new int[12]; arr[0] = 1; arr[1] = 1; // 遍歷陣列對其他元素賦值 for (int i = 2; i < arr.length; i++) { arr[i] = arr[i - 2] + arr[i - 1]; } // 如何獲取最後一個數, System.out.println(arr[arr.length - 1]); }
然後我們可以用第遞迴來做,
// 第2種方法:用遞迴求斐波那契數列
/*
* 分析: 1=fun(1) 1=fun(2) 2=fun(1)+fun(2) 3=fun(2)+fun(3)
*/
public static int fun(int num) {
if (num == 1 || num == 2) {
return 1;
} else {
return fun(num - 2) + fun(num - 1);
}
}
二、集合練習(約瑟夫環)
- 幸運數字
/* * 返回值型別為int * */ public static int getLuckNum(int num){ //建立集合1到num的物件 ArrayList<Integer> list=new ArrayList<>(); for(int i=1;i<=num;i++){ list.add(i); //儲存到集合中 } int count=1; //只要是3的倍數就remove掉 for(int i=0;list.size()!=1;i++){ //只要集合中人數超過1,就要不斷的殺 if(i==list.size()){ i=0; //如果i增長到集合最大的索引+1時,就重新歸0 } if(count%3==0){ list.remove(i--); } count++; } return list.get(0); }
三、
遞迴練習(1000的階乘所有零和尾部零的個數)
當然,如果我們直接使用以下方法來做的話是不可行的
/*
* int result=1; //這裡要從1開始,不能從0開始,因為任何數乘0都為0
* for(int i=1;i<=1000;i++){
* result=result*i;
* }
* System.out.println(result);
* //此方法不能使用,因為這樣計算的值(1000的階乘)超出int的取值範圍了
*/
所以我們需要這樣做,先去求出1000的階乘,然後再去統計有多少個0.
// 求出1000的階乘 BigInteger bi1 = new BigInteger("1"); for (int i = 1; i <= 1000; i++) { BigInteger bi2 = new BigInteger(i + "");// 轉換為字串型別的 bi1 = bi1.multiply(bi2); // 將bi1與bi2相乘的結果賦值給bi1 }
// 求出尾部所有的0
private static void demo2(BigInteger bi1) {
String str=bi1.toString();
StringBuilder sb=new StringBuilder(str);
str=sb.reverse().toString(); //鏈式程式設計
int count=0;
for(int i=0;i<str.length();i++){
if('0'!=str.charAt(i)){
break;
}else{
count++;
}
}
System.out.println(count);
}
// 求出所有的0
private static void demo1(BigInteger bi1) {
String str = bi1.toString();// 獲取字串表現形式
int count = 0;
for (int i = 0; i < str.length(); i++) {
if ('0' == str.charAt(i)) { // 如果字串中出現了0則計數器加1
count++;
}
}
System.out.println(count);
}
那麼如果我們用遞迴來做的話,這個問題就會非常簡單了,
//求出1000的階乘所有零和尾部零的個數,用遞迴做
public class h {
public static void main(String[] args) {
System.out.println(fun(1000));
}
public static int fun(int num){
if(num>0 && num<5){
return 0;
}else{
return num/5 + fun(num/5);
}
}
}
File類遞迴練習(統計該資料夾大小)
* 需求:,從鍵盤接收一個資料夾路徑,統計該資料夾大小
</pre><pre name="code" class="java">/*
* 從鍵盤接收一個資料夾路徑
* 定義一個無限迴圈
* 將鍵盤錄入的結果儲存並封裝成File物件
* 對File物件判斷
* 將資料夾路徑物件返回
*
*
* 統計該資料夾大小
* 1、定義一個求和變數
* 2、獲取該資料夾下所有的檔案和資料夾listFiles();
* 3、遍歷陣列
* 4、判斷是檔案就計算大小並累加
* 5、判斷是資料夾就遞迴呼叫
*
*
*/
public static void main(String[] args){
File dir=getDir();
System.out.println(getFileLength(dir));
}
public static File getDir(){
Scanner sc=new Scanner(System.in);
System.out.println("請輸入一個資料夾路徑");
while(true){
String line=sc.nextLine();
File dir=new File(line);
if(!dir.exists()){
System.out.println("目錄不存在");
}else if(dir.isFile()){
System.out.println();
}else{
return dir;
}
}
}
public static long getFileLength(File dir){
long len=0;
File[] files=dir.listFiles();
for(File file :files){
if(file.isFile()){
len=len+file.length();
}else{
len=len+getFileLength(file);
}
}
return len;
}
File類遞迴練習(刪除該資料夾)
* 需求:,從鍵盤接收一個資料夾路徑,刪除該資料夾
分析:
/*
* 1、獲取該資料夾下的所有檔案和資料夾
* 2、遍歷陣列
* 3、判斷是檔案直接刪除
* 4、如果是資料夾,遞迴呼叫
* 5、迴圈結束後,把控資料夾刪除
*
*/
public static void main(String[] args) {
File dir=a.getDir();
deleteFile(dir);
}
public static void deleteFile(File dir){
File[] subFiles=dir.listFiles();
for(File file:subFiles){
if(file.isFile()){
file.delete();
}else{
deleteFile(file);
}
}
//迴圈結束後把資料夾刪除掉
dir.delete();
}
File類遞迴練習(拷貝)
* 需求,從鍵盤接收兩個資料夾路徑,把其中一個資料夾中(包含內容)拷貝到另一個資料夾中
/*
* 1、在目標資料夾中建立原資料夾
* 2、獲取原資料夾中所有的檔案和資料夾,儲存在File陣列中
* 3、遍歷陣列
* 4、如果是檔案就用io流讀寫
* 5、如果是資料夾就遞迴呼叫
*
*/
public static void main(String[] args) throws IOException {
File src=a.getDir();
File dest=a.getDir();
if(src.equals(dest)){
System.out.println("目錄資料夾是原始檔夾的子資料夾");
}else{
copy(src,dest);
}
}
public static void copy(File src, File dest) throws IOException {
File newDir=new File(dest,src.getName());
newDir.mkdir();
File[] subFiles=src.listFiles();
for (File file : subFiles) {
if(file.isFile()){
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(new File(newDir,file.getName())));
int b;
while((b=bis.read())!=-1){
bos.write(b);
}
bis.close();
bos.close();
}else{
//如果是資料夾就遞迴呼叫
copy(file,newDir);
}
}
}
File類遞迴練習(按層級列印)
* 要求:,從鍵盤接收一個資料夾路徑,把資料夾中的所有檔案以及資料夾的名字按層級列印,
/*
* 1、獲取所有檔案和資料夾,返回的File陣列
* 2、遍歷陣列
* 3、無論是檔案還是資料夾,都需要直接列印
* 4、如果是資料夾,遞迴呼叫
*
*/
public static void main(String[] args) {
File dir=a.getDir();
printLev(dir,0);
}
public static void printLev(File dir,int level) {
File[] subFiles=dir.listFiles();
for (File file : subFiles) {
for(int i=0;i<=level;i++){
System.out.print("\t");
}
System.out.println(file);
if(file.isDirectory()){
printLev(file,level+1);
}
}
}