入門篇-其之十-流程控制之迴圈結構

2023-12-16 12:00:45

本文中使用到的工具是Intellij IDEA和JDK 8,需要安裝兩款工具的請檢視這兩篇教學:點我檢視安裝JDK8/11/17教學點我檢視安裝Intellij IDEA教學

假設輸出1~100之間的所有整數,正常情況下我們需要寫100行程式碼才能對所有數位輸出。

System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
// 其他數位輸出省略...
System.out.println(100);

雖然這種辦法能達到預期的效果,但是程式碼量屬實有點大(ᇂ_ᇂ|||)

為了解決上述問題,Java為我們提供了一個強大的控制結構——迴圈結構。

迴圈結構是一種常用的程式控制結構,它允許程式在執行的過程中反覆執行一段程式碼,直到滿足特定條件為止。迴圈結構可以大大簡化重複性任務的編寫,提高程式碼編寫效率和可讀性。

在Java中,迴圈結構主要由while迴圈、do-while迴圈、for迴圈組成。

一、while迴圈

while迴圈的語法格式如下:

while (條件表示式) {
    執行程式碼...
}

執行流程:如果條件表示式結果為true,此時進入while迴圈內部執行程式碼,直到while迴圈的條件表示式的結果為false為止。

while結構如下圖所示:

案例1:使用while迴圈解決1~100的輸出和1~100的和

我們先解決1~100的輸出,使用while需要回圈100次,我們可以在while迴圈外定義一個變數number並賦值為1,由於是1~100是遞增輸出,條件表示式需要設定為number <= 100

在迴圈體中,我們先將number的值進行輸出。但是此時number的值並沒有增加,因此每次在輸出後需要對number進行自增1的操作,即number++,部分程式碼如下:

int number = 1;
while (number <= 100) {
    System.out.println("number = " + number);
    number++;
}

這樣就完成了1~100的輸出,但是我們還需要輸出它們相加的和,我們可以對上述的程式碼進行進一步改造:

while迴圈外部再定義一個變數sum,預設值為0,用於儲存數位相加的和。

在迴圈體中,輸出語句後面實現兩數相加的操作:sum = sum + number;(簡寫為sum += number;

  • 第一次迴圈:sum = 0 + 1 = 1
  • 第二次迴圈:sum = 1 + 2 = 3
  • 第三次迴圈:sum = 3 + 3 = 6
  • 以此類推......

while迴圈內部即可完成1~100的計算,最終sum的結果直接到while迴圈外部進行輸出即可,完整程式碼如下:

/**
 * while迴圈--輸出1~100並求和
 *
 * @author iCode504
 * @date 2023-11-30
 */
public class WhileLoop1 {
    public static void main(String[] args) {
        // 1. 定義一個變數number用於輸出數位
        int number = 1;
        // 2. 定義一個變數sum用於儲存1~100相加的和
        int sum = 0;
        // 3. 定義while迴圈,條件表示式為number <= 100,需要保證number在while迴圈內相加
        while (number <= 100) {
            sum += number;
            System.out.println("number = " + number);
            number++;
        }
        System.out.println("sum = " + sum);
    }
}

執行結果符合我們的預期:

案例2:斐波那契數列

已知每對兔子(一雌一雄)每個月能生殖一對小兔子,每對兔子前兩個月沒有生育能力,從第三個月每個月能生一對小兔子,假設兔子不存在死亡現象,那麼從第一對剛出生兔子開始,第n個月以後會有多少隻兔子?

數學解法可以看這位老師的文章:點我檢視,我只能說一句:太強了,膜拜大佬!

根據上述題意可以得出:

  • 第1個月兔子無生育能力,因此兔子只有1對;
  • 第2個月兔子無生育能力,此時兔子仍為1對;
  • 第3個月兔子生育了一對兔子,此時兔子為2對;
  • 第4個月最開始的兔子又生育了一對兔子,此時兔子為3對;
  • 第5個月,最開始的兔子又生育了一對兔子,第三個月的兔子也生育了一對兔子,此時兔子為5對;

由此我們可以得出一個數列:

\[1,1,2,3,5…… \]

可以看出,從第三個數起,每個數都是前1個數和前兩個數相加得到的和。由此,我們可以得到一個通用公式:

\[f(n)=f(n-1)+f(n-2), n\geqslant3 \]

我們可以定義三個變數:number1number2totalNumber。其中number1number2儲存前兩個月兔子的數量,totalNumber儲存前兩月兔子數量的和(也就是上述公式的實現),具體實現程式碼如下:

import java.util.Scanner;

/**
 * while迴圈解決斐波那契數列
 *
 * @author iCode504
 * @date 2023-12-11
 */
public class FibonacciSequence {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("請輸入月數: ");
        int monthNumber = scanner.nextInt();

        // number1和number2代表前兩個月兔子的數量
        int number1 = 1, number2 = 1;
        // i的含義是從第三個月開始繁殖。totalNumber用於計算前兩個月兔子的數量
        // totalNumber初始化值為1的目的:如果使用者輸入的月數為1或2,此時兔子對數為1
        int i = 3, totalNumber = 1;
        // 限制條件:從第三個月開始計算到第monthNumber個月
        while (monthNumber > 2 && i <= monthNumber) {
            // 計算前兩個月兔子總數
            totalNumber = number1 + number2;
            // number1儲存i-2個月兔子數量,用於下一輪迴圈的運算
            number1 = number2;
            // number2儲存i-1個月兔子數量,用於下一輪迴圈的運算
            number2 = totalNumber;
            i++;
        }
        System.out.println("第" + monthNumber + "個月兔子的數量是" + totalNumber + "對");
    }
}

執行結果:

當然,迴圈只是解決斐波那契數列的一種方式,它還可以使用遞迴的方式解決。後續講到方法的時候還會講到這個問題的遞迴解法。

二、do-while迴圈

do-while迴圈的語法格式如下:

do {
    執行程式碼...
} while (條件表示式);

執行流程:先執行do內部的程式碼,內部程式碼執行完畢以後,再對while中的條件表示式進行判斷,如果條件表示式為true,再次進入do內部執行程式碼;如果條件表示式為false,此時就跳出do-while迴圈。

while迴圈相比,do-while迴圈即使其條件表示式為false,也會執行一次do內部的程式碼,因為它會先執行do內部的程式碼再進行條件判斷。

do-while迴圈的執行流程如下圖所示:

案例:計算一個數的所有因子之和(不包括1和自身)。輸入一個正整數,輸出其所有因子之和。

例如:

  • 正整數6的所有因子是:2,3。因此所有的因子的和是\(2 + 3 = 5\)
  • 正整數20的所有因子是:2,4,5,10。所有因子的和是\(2+4+5+10=21\)

如果使用do-while迴圈來解決這個問題,我們首先需要確定迴圈的範圍是什麼?

其實題目中已經告訴我們了一個關鍵點:不包括1和自身。那麼由此可以確定迴圈的範圍是:\([2, number)\)

如何確定上述區間的數位是正整數number的因子呢?其實很簡單,只需要判斷這個數位能否被number整除即可。

由於我們輸入的是正整數,需要在執行迴圈做一手判斷,如果不是正整數,需要給出一個提示。

綜合上述內容,程式碼如下:

import java.util.Scanner;

/**
 * do-while解決一個數所有因子的和
 *
 * @author iCode504
 * @date 2023-12-15
 */
public class DoWhileDemo1 {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("請輸入一個正整數: ");
        int number = scanner.nextInt();
        // 正整數判斷
        if (number > 0) {
            // 定義一個變數sum,用於儲存所有因子的和
            int sum = 0;
            // 由於正整數中因子不包含1和數位本身,因此迴圈需要從2開始,計算到number - 1
            int i = 2;
            do {
                // 判斷條件:i能被number整除的,那麼i就是number的因子
                if (number % i == 0) {
                    sum += i;
                }
                i++;
            } while (i < number);
            System.out.println("正整數" + number + "所有因子的和是: " + sum);
        } else {
            System.out.println("您輸入的不是正整數!!!");
        }
    }
}

執行結果:

在開發中,使用do-while迴圈的頻率要比while迴圈少很多。這主要是因為do-while迴圈本身是先執行迴圈體,然後再進行條件判斷。即使條件判斷結果是falsedo-while也執行了一次迴圈體,這可能會導致不必要的計算和操作。

三、普通for迴圈

普通for迴圈的語法格式如下:

for (初始化表示式; 條件表示式; 迭代表示式) {
    執行程式碼...
}

for迴圈的執行流程如下圖所示:

這裡解釋一下for內部的三個表示式:

1. 初始化表示式,指的是初始化Java變數表示式,即資料型別 變數名 = 變數值

例如:int i = 0;,或者把int i寫到for迴圈之前,然後在for迴圈第一個位置將i = 0補齊即可。

當然,初始化表示式也可以同時定義多個變數,例如:int i = 0, j = 0;

2. 條件表示式,如果計算結果為true,就進入for迴圈內部執行程式碼,如果條件表示式為false,就會跳出for迴圈。

一般而言,條件表示式和初始化表示式中定義的變數有關。例如:i < 100i > -30等等。

3. 迭代表示式,絕大多數情況下針對初始化表示式定義的變數進行增加或減少的操作。

以前面定義的初始化表示式int i = 0;為例,假設讓變數的值增加,我們可以使用如下方式:

i++;	// 自增1
++i;	// 自增1
i += number;	// 讓i每次增加number

4. 一般在寫for迴圈程式碼時,推薦將初始化表示式、條件表示式、迭代表示式都寫上。

事實上,不寫上述三個表示式也會執行for迴圈程式碼,但是如果在for迴圈內部不寫合理的條件判斷的話,很容易造成死迴圈的情況的發生。

那麼for迴圈的執行流程是怎麼樣的呢?

  • 在首次執行for迴圈的時候,先執行初始化表示式,然後根據條件表示式結果進行判斷,如果條件表示式為true,則進入for迴圈內部執行程式碼,如果條件表示式為false就跳出for迴圈。在執行完for迴圈內部程式碼以後,會針對前面初始化表示式的變數進行迭代操作(常見的是變數相加/相減操作)。
  • 後續執行for迴圈的時候,就會根據for迴圈迭代表示式的計算結果到條件表示式中進行比較,如果比較結果為true執行for內部程式碼,反之就會跳出for迴圈。

這裡舉兩個案例來說明一下for迴圈的使用:

案例1:求1~100(包含100)所有的偶數和

解決本題的關鍵點是偶數的獲取,判斷一個數是否是偶數,即數位對2求餘等於0,再定義一個變數sum對所有符合條件的偶數累加即可。

/**
 * for計算1~100所有偶數和
 *
 * @author iCode504
 * @date 2023-12-15
 */
public class NumberPrint {
    public static void main(String[] args) {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            // 偶數判斷條件:對2求餘是否等於0
            if (i % 2 == 0) {
                // 偶數累加
                sum += i;
            }
        }
        System.out.println("1~100之間所有的和: " + sum);
    }
}

執行結果:

案例2:水仙花數是指一個3位數,它的每個數位上的數位的3次冪之和等於這個數的本身。例如:

\[1^3 + 5^3+3^3 = 153 \]

請使用for迴圈列舉所有的水仙花數。

1. 確定範圍:水仙花是一個三位數,三位數的數位範圍在\([100, 999]\)區間內

2. 個位、十位、百位數的獲取:

\[百位數 = 數位 / 100 \]

\[十位數 = 數位/10\%10 \]

\[個位數=數位\%10 \]

3. 符合水仙花數的條件:

\[數位 = 百位數^3+十位數^3+個位數^3 \]

綜合以上的分析,使用for迴圈的程式碼如下圖所示:

/**
 * for迴圈列舉水仙花數
 *
 * @author iCode504
 * @date 2023-12-15
 */
public class NarcissisticNumber {
    public static void main(String[] args) {
        // 定義三個變數a, b, c分別儲存百位數、十位數、個位數
        int a, b, c;
        // 迴圈範圍設定在[100, 999] --> [100, 1000)
        for (int i = 100; i < 1000; i++) {
            // 百位數、十位數、個位數的獲取
            a = i / 100;
            b = i / 10 % 10;
            c = i % 10;
            // 水仙花數的判斷條件
            if (i == a * a * a + b * b * b + c * c * c) {
                System.out.println(i);
            }
        }
    }
}

執行結果即\([100, 999]\)以內的所有水仙花數:

正如這節標題:「普通for迴圈」,其實JDK 5還為我們設計了foreach迴圈(也稱作增強for迴圈),這類迴圈主要用於遍歷陣列和列表等結構,使用foreach迴圈會簡化程式碼結構,在後續學習陣列是我們會用到它,敬請期待°꒰๑'ꀾ'๑꒱°

四、死迴圈

死迴圈,即條件表示式計算結果恆定為true而不斷執行迴圈內部的程式碼。是一種無法自行終止的迴圈。在死迴圈中,程式會反覆執行同一段程式碼,而且永遠無法跳出這個迴圈,除非手動中斷程式或者遇到未處理的異常。

下面使用上述三種迴圈演示以下死迴圈:

// while形式的死迴圈
while (true) {
    System.out.println("我是死迴圈");
}
// do-while形式的死迴圈
do {
    System.out.println("我是死迴圈");
} while (true);
// for形式的死迴圈:不寫初始化表示式和迭代表示式,條件表示式為true
for (; true; ) {
    System.out.println("我是死迴圈");
}

執行程式碼的過程中,如果不進行人為停止程式,它們就會不停輸出「我是死迴圈」:

死迴圈會導致程式無法正常執行其他任務,並且可能會佔用大量資源。在編寫回圈結構時,務必要保證正確設定迴圈條件和提供適當的跳出機制,以避免死迴圈的發生。

五、Intellij IDEA關於迴圈的快捷鍵

1. 在Intellij IDEA中,如果快捷生成一個迴圈結構,可以輸入fori,然後會出現一個提示,按回車即可生成一個for迴圈結構。這個for迴圈是從0開始的:

2. 如果想生成一個從0~n的for迴圈,可以使用n.for快捷生成。例如:如果我想生成0~100之間的迴圈,可以直接按100.for,出現提示後直接按回車即可生成這個區間的for迴圈:

3. 輸入n.forr可以生成一個從n到0依次遞減的for迴圈,還是以100.forr為例,生成的效果如下圖所示:

4. 在編寫程式碼的過程中,如果條件表示式可以確定的話,可以直接使用條件表示式.while快捷生成一個while迴圈,例如: