1. 程式人生 > 程式設計 >經典演演算法(1):氣泡排序及其優化

經典演演算法(1):氣泡排序及其優化

(轉載)原文連結:blog.csdn.net/weixin_4357…

氣泡排序

在平常的學習中用到了氣泡排序,這篇部落格對氣泡排序演演算法進行了詳細的程式碼實現,並且進行了兩次優化,供大家一起參考學習。

目錄

一、什麼是氣泡排序

二、氣泡排序演演算法的思想

三、程式碼實現

1.第一次優化

2.第二次優化

一、什麼是氣泡排序

氣泡排序是一種最基礎的交換排序。氣泡排序就像水冒泡,小(大)的元素經過不斷的交換由水底慢慢的浮到水的頂端。

二、氣泡排序演演算法的思想

我們從左邊開始把相鄰的兩個數兩兩做比較,當一個元素大於右側與它相鄰的元素時,交換它們之間位置,反之,它們之間的位置不發生變化。氣泡排序是一種穩定的排序演演算法。

(注:此動圖來源於網路)

時間複雜度 空間複雜度
O(n^2) O(1)

三、程式碼實現

public class BubbleSort1 {
    public static void main(String[] args) {
        System.out.println("輸入要排序的值,輸入的每個值用逗號隔開:");
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();
        // 將字串按照","拆分成字串陣列
        String[] strArray = str.split(","
); // 新建陣列用來儲存拆分出來的每個值 int[] array = new int[strArray.length]; // 給陣列迴圈遍歷賦值 for (int i = 0; i < strArray.length; i++) { array[i] = Integer.parseInt(strArray[i]); } System.out.println("排序前的陣列:" + Arrays.toString(array)); // 排序 sort(array); System.out.println("排序後的陣列:"
+ Arrays.toString(array)); } /** * 用氣泡排序演演算法對陣列進行排序 * @param array */ private static void sort(int[] array) { // array.length - 1是因為最後一輪不需要排序 for (int i = 0; i < array.length - 1; i++) { System.out.println("第" + (i + 1) + "趟"); // array.length - i是因為每一輪都能確定排序好一個數 for (int j = 0; j < array.length - 1 - i; j++) { int temp = 0; if (array[j] > array[j + 1]) { temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } System.out.println(" 第" + (j + 1) + "次:" + Arrays.toString(array)); } } } } 複製程式碼

演演算法執行結果:

輸入要排序的值,輸入的每個值用逗號隔開:
6,9,8,3,2,11,15,16,18,19
排序前的陣列:[6,19]
第1趟
  第1次:[6,19]
  第2次:[6,19]
  第3次:[6,19]
  第4次:[6,19]
  第5次:[6,19]
  第6次:[6,19]
  第7次:[6,19]
  第8次:[6,19]
  第9次:[6,19]
第2趟
  第1次:[6,19]
第3趟
  第1次:[3,6,19]
  第2次:[3,19]
  第3次:[3,19]
  第4次:[3,19]
  第5次:[3,19]
  第6次:[3,19]
  第7次:[3,19]
第4趟
  第1次:[2,19]
  第2次:[2,19]
  第3次:[2,19]
  第4次:[2,19]
  第5次:[2,19]
  第6次:[2,19]
第5趟
  第1次:[2,19]
第6趟
  第1次:[2,19]
第7趟
  第1次:[2,19]
第8趟
  第1次:[2,19]
第9趟
  第1次:[2,19]
排序後的陣列:[2,19]

複製程式碼

從上圖中的執行結果可以看出,第5趟排序後就已經是有序的了,可是演演算法還是進行了後面的排序,因此對演演算法進行以下的第一次優化。

1.第一次優化

增加一個標記(flag),每次發生交換,就進行標記,如果某次迴圈完沒有標記,則說明已經完成排序,陣列有序,剩下的幾趟排序就不需要再去執行了,可以提前結束排序。

public class BubbleSort2 {
    public static void main(String[] args) {
        System.out.println("輸入要排序的值,輸入的每個值用逗號隔開:");
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();

        // 將字串按照",");
        // 新建陣列用來儲存拆分出來的每個值
        int[] array = new int[strArray.length];
        // 給陣列迴圈遍歷賦值
        for (int i = 0; i < strArray.length; i++) {
            array[i] = Integer.parseInt(strArray[i]);
        }

        System.out.println("排序前的陣列:" + Arrays.toString(array));

        // 排序
        sort(array);
        System.out.println("排序後的陣列:" + Arrays.toString(array));
    }

    /**
     * 用氣泡排序演演算法對陣列進行排序
     *
     * @param array
     */
    private static void sort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            System.out.println("第" + (i + 1) + "趟");
            // 優化氣泡排序,增加判斷位,有序標記,每一輪的初始是true
            boolean flag = true;
            for (int j = 0; j < array.length - 1 - i; j++) {
                // 找最小數,如果前一位比後一位大,則交換位置
                int temp = 0;
                if (array[j] > array[j + 1]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    // 有元素交換,所以不是有序,標記變為false
                    flag = false;
                }
                System.out.println("  第" + (j + 1) + "次:" + Arrays.toString(array));
            }
            // 說明上面內層for迴圈中,沒有交換任何元素,直接跳出外層迴圈
            if (flag) {
                break;
            }
        }
    }
}
複製程式碼

演演算法執行結果:

輸入要排序的值,輸入的每個值用逗號隔開:
6,19]
複製程式碼

從第一次優化後的結果可以看出,在每趟排序中,右面的許多元素已經是有序的結果了,可演演算法還是進行後面數值的排序,因此進行第二次優化。

2.第二次優化

定義arrBoundary 是無序陣列的邊界,每次比較比到這裡為止,不需要進行後面的排序了。

public class BubbleSort3 {
    public static void main(String[] args) {
        System.out.println("輸入要排序的值,輸入的每個值用逗號隔開:");
        Scanner input = new Scanner(System.in);
        String str = input.nextLine();

        // 將字串按照',"拆分成字串陣列
        String[] strArray = str.split(",");
        // 新建陣列用來儲存拆分出來的每個值
        int[] array = new int[strArray.length];
        // 給陣列迴圈遍歷賦值
        for (int i = 0; i < strArray.length; i++) {
            array[i] = Integer.parseInt(strArray[i]);
        }

        System.out.println("排序前的陣列:" + Arrays.toString(array));

        // 排序
        sort(array);
        System.out.println("排序後的陣列:" + Arrays.toString(array));
    }

    /**
     * 用氣泡排序演演算法對陣列進行排序
     *
     * @param array
     */
    private static void sort(int[] array) {

        // 用來交換的臨時數
        int temp = 0;
        // 最後一次交換的下標
        int lastSwapIndex = 0;
        // 無序陣列的邊界,每次比較比到這裡為止
        int arrBoundary = array.length - 1;

        for (int i = 0; i < array.length - 1; i++) {
            System.out.println("第" + (i + 1) + "趟");
            // 優化氣泡排序,增加判斷位,有序標記,每一輪的初始是true
            boolean flag = true;
            for (int j = 0; j < arrBoundary; j++) {
                // 找最小數,如果前一位比後一位大,則交換位置
                if (array[j] > array[j + 1]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    // 有元素交換,所以不是有序,標記變為false
                    flag = false;
                    // 最後一次交換元素的位置
                    lastSwapIndex = j;
                }
                System.out.println("  第" + (j + 1) + "次:" + Arrays.toString(array));
            }

            // 把最後一次交換元素的位置賦值給無序陣列的邊界
            arrBoundary = lastSwapIndex;
            // 說明上面內層for迴圈中,沒有交換任何元素,直接跳出外層迴圈
            if (flag) {
                break;
            }
        }
    }
}
複製程式碼

演演算法執行結果:

輸入要排序的值,輸入的每個值用逗號隔開:
6,19]
第5趟
排序後的陣列:[2,19]
複製程式碼

注:氣泡排序裡面需要交換兩個元素的位置,交換兩個元素可以用異或的操作,這樣不需要建立第三個變數,減少記憶體開銷。

可以對排序過程中交換兩個元素的方法修改如下:

if (array[j] > array[j + 1]) {
                    array[j + 1] ^= array[j];
                    array[j] ^= array[j + 1];
                    array[j + 1] ^= array[j];
                }
複製程式碼

原文連結:blog.csdn.net/weixin_4357…

END