“嗨,Amigo。今天 Bilaabo 將向您介紹遞歸。”

遞歸 - 1

如您所知,在 Java 中,一些方法會調用其他方法。此外,當一個方法被調用時,特定的參數被傳遞給它,但是方法的局部變量在它運行時採用特定的值。

“嗯。”

“正如你所知,不同方法的內部變量是相互獨立的。”

“嗯。”

“所以想像一下方法調用自身的情況。這稱為遞歸。例如:”

例子
public static void main(String[] args)
{
 countDown(10);
}

public static void countDown(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown(x - 1);
 }
}
屏幕輸出:
10
9
8
7
6
5
4
3
2
1
Boom!

“我可以看到該方法在代碼中調用了自身,但老實說我不明白髮生了什麼。”

“好吧,當調用不同的方法時會發生同樣的事情。”

“不,我問的是變量會發生什麼?它們的值會怎樣?我們如何退出方法?還是一次性退出所有內容?”

“天哪。一切都簡單多了。想像一下,調用自身的方法被乘以了很多次。那麼我們就會遇到類似的情況:”

遞歸方法調用 到底發生了什麼
public static void main(String[] args)
{
 countDown(10);
}

public static void countDown(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown(x - 1);
 }
}
public static void main(String[] args)
{
 countDown1(10);
}

public static void countDown1(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown2(x - 1);
 }
}
public static void countDown2(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown3(x - 1);
 }
}
public static void countDown3(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown4(x - 1);
 }
}

public static void countDown4(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  countDown5(x - 1);
 }
}
屏幕輸出: 屏幕輸出:
3
2
1
Boom!
3
2
1
Boom!

“換句話說,每次調用一個方法(甚至調用它自己)時,都會創建新變量來存儲該方法的數據。沒有共享變量。”

“每次調用時,都會在內存中創建具有新值的方法參數的另一個副本。當我們返回到舊方法時,它的變量會在那裡使用。換句話說,在遞歸期間我們實際上調用了另一個方法,但是使用和我們的代碼一樣!

“我明白了。退出這種方法是如何工作的?也許是一個例子?”

“好的。一個例子勝過一千個字。”這是你的例子:

遞歸方法調用 遞歸方法調用
public static void main(String[] args)
{
 print(3);
}

public static void print(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  print(x - 1);
  System.out.println(x);
 }
}
public static void main(String[] args)
{
 print1(3);
}

public static void print1(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  print2(x - 1);
  System.out.println(x);
 }
}

public static void print2(int x)
{
 if (x <= 0)
  System.out.println("Boom!");
 else
 {
  System.out.println(x);
  print3(x - 1);
  System.out.println(x);
 }
}

…
屏幕輸出: 屏幕輸出:
3
2
1
Boom!
1
2
3
3
2
1
Boom!
1
2
3

“好的。我想我明白了。為什麼我們需要遞歸?”

“有很多很多任務可以分成與原始任務相同的單獨子任務。例如,您需要遍歷 XML 樹的所有元素。每個元素可以有幾個子元素,它們有自己的子元素自己的子元素。”

“或者你需要顯示一個目錄及其所有子目錄中的文件列表。所以你寫了一個方法來顯示當前目錄的文件。然後要獲取所有子目錄的文件,你調用你的方法使用不同的論點:一個子目錄。”

“例如:”

顯示目錄及其子目錄中的所有文件
public static void main(String[] args)
{
 printAllFiles(new File("c:/windows/"));
}

public static void printAllFiles(File dir)
{
 for (File file : dir.listFiles())
 {
  if (file.isDirectory())
   printAllFiles(file);
  else
   System.out.println(file.getAbsolutePath());
 }
}

“第 8 行——我們獲取 dir 目錄中所有文件(和目錄)的列表。”

“第 10-11 行——如果文件實際上是一個目錄,那麼我們再次調用printAllFiles,但這次有另一個參數:子目錄。”

“第 13 行——我們顯示當前文件的名稱。”

“好的。我想我明白了。謝謝你,Bilaabo。”