數(shù)據(jù)結(jié)構(gòu)與算法學(xué)習(xí)3-冒泡排序

不詩意的女程序猿不是好廚師~
轉(zhuǎn)載請注明出處【From 李詩雨---https://blog.csdn.net/cjm2484836553/article/details/95004540

源碼地址見github:https://github.com/junmei520/DataStructureStudy/tree/master/src/algorithms

1.冒泡排序概念

排序序列從前向后(從下標(biāo)較小的元素開始),依次比較相鄰元素的值,若發(fā)現(xiàn)逆序則交換,使值較大的元素逐步移到后部,就像水底的氣泡一樣逐漸往上冒。

2.舉個栗子并總結(jié)規(guī)則

下面我們以 2, 8, -1, 20, -6 這組數(shù)據(jù)為例,來一步一步進(jìn)行冒泡排序:


image

最終排序后結(jié)果:-6 ,-1 ,2 ,8 ,20

由此我們總結(jié)出一些冒泡排序的規(guī)則
(1)一共進(jìn)行了【數(shù)組的大小-1】次大的循環(huán)。
(2)每一趟排序的次數(shù)在逐漸減少。

3.代碼實(shí)現(xiàn)基礎(chǔ)的冒泡排序

3.1先從冒泡排序的演變過程來一步一步分析

(此部分完整代碼 對應(yīng) github上的 algorithms.BubbleSort1 類)
還是以上面的數(shù)組為實(shí)例,我們來一步一步分析:
第一趟排序 把最大的數(shù)排在最后 需要比較4次(即【arr.length-1】次

 //第一趟排序 把最大的數(shù)排在最后
        // 需要比較4次(即【arr.length-1】次)
        int temp = 0;
        for (int j = 0; j < arr.length - 1; j++) {
            //如果前面的數(shù)比后面的數(shù)大,就進(jìn)行交換
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        System.out.println("第一趟后的數(shù)組為:" + Arrays.toString(arr));

第二趟排序 把第二大的數(shù)排在倒數(shù)第二位
這次的比較次數(shù)比以第一趟的少1次,需要比較3次(即【arr.length-1-1】次)

 //第二趟排序 把第二大的數(shù)排在倒數(shù)第二位
        //這次的比較次數(shù)比以第一趟的少1次,需要比較3次(即【arr.length-1-1】次)
        for (int j = 0; j < arr.length - 1 - 1; j++) {
            //如果前面的數(shù)比后面的數(shù)大,就進(jìn)行交換
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        System.out.println("第二趟后的數(shù)組為:" + Arrays.toString(arr));

第三趟排序 把第三大的數(shù)排在倒數(shù)第三位
這次的比較次數(shù)比以第一趟的少2次,需要比較2次(即【arr.length-1-2】次)

 //第三趟排序 把第三大的數(shù)排在倒數(shù)第三位
        //這次的比較次數(shù)比以第一趟的少2次,需要比價2次(即【arr.length-1-2】次)
        for (int j = 0; j < arr.length - 1 - 2; j++) {
            //如果前面的數(shù)比后面的數(shù)大,就進(jìn)行交換
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        System.out.println("第三趟后的數(shù)組為:" + Arrays.toString(arr));

第四趟排序 把第四大的數(shù)排在倒數(shù)第四位
這次的比較次數(shù)比以第一趟的少3次,需要比較1次(即【arr.length-1-3】次)

//第四趟排序 把第四大的數(shù)排在倒數(shù)第四位
        //這次的比較次數(shù)比以第一趟的少3次,需要比價1次(即【arr.length-1-3】次)
        for (int j = 0; j < arr.length - 1 - 3; j++) {
            //如果前面的數(shù)比后面的數(shù)大,就進(jìn)行交換
            if (arr[j] > arr[j + 1]) {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
        System.out.println("第四趟后的數(shù)組為:" + Arrays.toString(arr));

打印結(jié)果:


image

3.2總結(jié)規(guī)律并合并簡化代碼

(此部分完整代碼 對應(yīng) github上的 algorithms.BubbleSort2 類)
通過總結(jié),我們可以看出,這四趟的比較代碼基本相同,唯一不同的就是這里:

image

所以我們可以把不同的抽取出去,把相同的包起來,則可以改造成如下樣子:

//創(chuàng)建原始數(shù)組
        int[] arr = {2, 8, -1, 20, 80};

        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //如果前面的數(shù)比后面的數(shù)大,就進(jìn)行交換
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            System.out.println("第" + (i + 1) + "趟后的數(shù)組為:" + Arrays.toString(arr));
        }

打印結(jié)果:


image

4.對冒泡排序進(jìn)行適當(dāng)?shù)膬?yōu)化

4.1通過實(shí)例發(fā)現(xiàn)問題

先舉個需要優(yōu)化的例子:比如把 2,8,-1,20,80按從小到的順序進(jìn)行排序
一步一步來分析:


image

此時我們發(fā)現(xiàn)了問題,其實(shí)第三趟排序數(shù)組并沒有發(fā)生任何變化,第四趟變化其實(shí)是多余的操作。我們本可以在第三趟排序后就提前結(jié)束冒泡排序的。

4.2優(yōu)化的具體代碼實(shí)現(xiàn)

(此部分完整代碼 對應(yīng) github上的 algorithms.BubbleSort3 類)
思路:
根據(jù)上面的分析 我們可以定下一個這樣的規(guī)則:如果某趟排序中,沒有發(fā)生過一次交換,就可以提前結(jié)束冒泡排序,這個就是優(yōu)化的方法。
那么我們不妨增加一個boolean 型的標(biāo)記 flag,初始值為false , 如果某趟排序中進(jìn)行了次序交換則把flag置為true。在一趟排序結(jié)束后,就判斷如果flag為false(說明此趟排序中沒有發(fā)生過一次交換),則提前退出冒泡排序;如果flag為true,則重置為false,繼續(xù)進(jìn)行下一趟比較。
我們就以 2,8,-1,20,80 這組數(shù)據(jù)集為例,沒有優(yōu)化前打印結(jié)果是:

image

優(yōu)化后的代碼為:

 //創(chuàng)建原始數(shù)組
        int[] arr = {2, 8, -1, 20, 80};

        boolean flag = false;//用于記錄一趟排序中是否進(jìn)行過交換
        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //如果前面的數(shù)比后面的數(shù)大,就進(jìn)行交換
                if (arr[j] > arr[j + 1]) {
                    flag = true;  //只要在某趟排序中進(jìn)行了交換,就置為true
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            System.out.println("第" + (i + 1) + "趟后的數(shù)組為:" + Arrays.toString(arr));

            //一趟比較結(jié)束后,判斷flag的值
            if (!flag) { //如果為false,則可以提前結(jié)束冒泡排序(說明此趟排序中一次交換都沒有)
                return;
            } else { //如果為true,則重置為false
                flag = false;
            }

        }

優(yōu)化后的打印結(jié)果:


image

果然少進(jìn)行了一趟排序。

5.將冒泡排序封裝成一個方法。

(此部分完整代碼 對應(yīng) github上的 algorithms.BubbleSort4 類)
細(xì)心的我們可能已經(jīng)發(fā)現(xiàn),上面的代碼太過于零散,那么我們不妨把它封裝成一個方法,這樣當(dāng)數(shù)組數(shù)據(jù)發(fā)生變化時,我們只要調(diào)用方法就可以了。

public class BubbleSort4 {
    public static void main(String[] args) {
        //創(chuàng)建原始數(shù)組
        int[] arr = {2, 8, -1, 20, 80};

        //測試冒泡排序方法
        System.out.println("排序前:" + Arrays.toString(arr));
        bubbleSort(arr);
        System.out.println("排序后:" + Arrays.toString(arr));
    }

    /**
     * 封裝的冒泡排序方法
     */
    private static void bubbleSort(int[] arr) {
        boolean flag = false;//用于記錄一趟排序中是否進(jìn)行過交換
        int temp = 0;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                //如果前面的數(shù)比后面的數(shù)大,就進(jìn)行交換
                if (arr[j] > arr[j + 1]) {
                    flag = true;  //只要在某趟排序中進(jìn)行了交換,就置為true
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
//            System.out.println("第" + (i + 1) + "趟后的數(shù)組為:" + Arrays.toString(arr));

            //一趟比較結(jié)束后,判斷flag的值
            if (!flag) { //如果為false,則可以提前結(jié)束冒泡排序(說明此趟排序中一次交換都沒有)
                return;
            } else { //如果為true,則重置為false
                flag = false;
            }
        }
    }
}

源碼地址見github:https://github.com/junmei520/DataStructureStudy/tree/master/src/algorithms

積累點(diǎn)滴,做好自己~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容