常問的幾個基礎排序,要不再複習一下?

Github 地址
排序,不管是日常開發還是面試中,都會被光顧,雖然現在 jdk 的集合中提供了排序的方法,但是我們也得去熟悉一些基礎的排序算法,這裏筆者給大家分享五個常問的基礎排序,冒泡、選擇、插入、希爾、快排。

冒泡排序

冒泡排序,顧名思義就是排序元素時像冒泡一樣,把最大或者最小慢慢比較到數組尾部,實現排序的方法。具體就是,如果有一個長度爲 n 的數組 num,將 num[0] 與 num[1] 比較,如果 num[0] > num[1] ,則交換位置,反之則不交換。再比較 num[1] 和 num[2], 根據大小決定位置,一直交換到數組結束。那麼 num[n-1] 一定是數組中最大的。再次做上述比較,那麼 num[n-2] 一定是第二大的,一直循環直到整個數組排序完成。 下圖只展示冒第一個泡。

在這裏插入圖片描述

public int[] order(int[] num){
        if (num.length == 0){
            return null;
        }

        // -1 是因爲我們比較 i 和 i+1,防止數組越界
        for (int i = 0; i < num.length -1 ; i++) {
            // 因爲第 num.length - i 到 num.length 的數字肯定是排序好的
            // 所以只用比到 num.length - i
            for (int j = 0; j < num.length - i - 1 ; j++) {
                if (num[j]>num[j+1]){
                    int temp = num[j];
                    num[j] = num[j+1];
                    num[j+1] = temp;
                }
            }
        }

        return num;
    }

選擇排序

選擇排序,就是第一次選擇數組中最小的與第一個交換,第二次選擇第二小的與第二個元素交換,直到交換到最後一個。

在這裏插入圖片描述

public int[] order(int[] num){
        if (num.length == 0){
            return null;
        }

        for (int i = 0; i < num.length; i++) {
            int minIndex = i;
            // 因爲前 i 位肯定是排序好的,所以只需要從 i 位開始找
            for (int j = i; j < num.length ; j++) {
                if (num[j] < num[minIndex]){
                    minIndex = j;
                }
            }
            int temp = num[i];
            num[i] = num[minIndex];
            num[minIndex] = temp;

        }
        return num;
    }

插入排序

插入排序是從拿第二個元素開始,與左邊的元素挨個比較,找到比自己大的元素放,然後把自己放到該元素左邊,如果沒有就不換位置,再從第三個元素開始,直到排序完成。

在這裏插入圖片描述

public int[] order(int[] num){
        if (num.length == 0 || num.length == 1){
            return num;
        }
        
        for (int i = 1; i < num.length; i++) {
            int changeIndex = i;
            for (int j = i; j > 0; j--) {
                if (num[changeIndex] < num[changeIndex - 1]){
                    int temp = num[changeIndex];
                    num[changeIndex] = num[changeIndex-1];
                    num[changeIndex-1] = temp;
                    changeIndex--;
                }else {
                    // 因爲是從選擇元素的左邊第一個開始比較
                    // 左邊已經排序完成,如果選擇元素大於已經要比較的元素可以直接退出比較
                    break;
                }
            }
        }
        return num;
    }

希爾排序

什麼是希爾排序呢?希爾排序是插入排序的改進版,我們可以看到,上面的插入排序在什麼時候排序會比較快呢?首先,和所有排序一樣,元素的個數少時,還有呢?我們可以看到,當數組基本有序時,那麼插入排序就會更快。所以希爾排序是什麼改進的呢?希爾排序將數組按照增量分割成若干個小組,利用插入排序完成排序,然後變小增量,再次分割並排序(這裏的分割只是邏輯上的分割,並沒有真正將數組分成幾個新的數組)。下面來詳細說一下:

在這裏插入圖片描述

先解釋一下,增量爲每組數組兩個元素之間下標差值,一般來說第一次增量爲數組長度的一半,第二次分組的增量爲上次的增量的一半,一直到增量爲 1。可以看到,第一次分組插入排序後,每組有序,數組大致有序,我們再接着分組:

在這裏插入圖片描述

如果再次分組的話,grow = grow/2 = 1,這樣的增量爲1,就不需要分組了,我們可以看到現在的數組比原數組有序多了,使用現在的數組比進行插入排序會比原數組快很多。

代碼表示(其實就是分組使用插入排序):

public int[] order(int[] num){
        if (num.length == 0 || num.length == 1){
            return num;
        }

        for (int grow = num.length/2; grow > 0 ; grow/=2) {
            for (int j = grow; j < num.length; j++) {
                int k = 1;
                int changeIndex = j;
                while (j - grow * k >= 0){
                    if (num[changeIndex] < num[changeIndex - grow]){
                        int temp = num[changeIndex];
                        num[changeIndex] = num[changeIndex - grow];
                        num[changeIndex - grow] = temp;
                        changeIndex -= grow;
                    }else {
                        // 因爲是每組元素從選擇元素的左邊第一個開始比較
                        // 左邊已經排序完成,如果選擇元素大於已經要比較的元素可以直接退出比較
                        break;
                    }
                    k++;
                }
            }
        }
        return num;
    }

快速排序

快速排序就是我們經常聽到的快排,那麼快排是怎麼對數組進行排序的呢?快排中有比較重要的三個變量,基準、左指針,右指針。基準一般是數組的第一個元素,左指針指第一個元素,右指針指最後一個元素,分別從左右指針指的元素與基準比較,比基準大的放右邊,比基準小的放左邊。這樣到最後,就會找到一個數,這個數的左邊都比這個數小,右邊都比這個數大,然後再遞歸按照上面的方法分別遍歷這個數的左區間和右區間,一直遍歷到左右區間只有一個數時,則排序完成。具體見下圖:

在這裏插入圖片描述

接着遞歸左區間和右區間,左區間的基準元素爲 1,左指針元素爲 1,右指針元素爲 4,右區間的基準元素爲 7,左指針元素爲 7,右指針元素爲 8,一直遞歸到所有的子左區間和子右區間元素個數爲 1,則排序完成。具體代碼如下:

public int[] order(int[] num){
        if (num.length == 0 || num.length == 1){
            return num;
        }
        sort(num,0,num.length-1);
        return num;
    }

public void sort(int[] num,int l,int r){
        // 證明左右區間元素爲 1
        if (l > r){
            return;
        }

        // 因爲 l,r 還需要給左右區間確定範圍,所以使用臨時變量移動指針
        int index = l,left = l,right=r;

        while (left < right){
            // 先比較右邊
            while (num[index]<=num[right] && left<right){
                right--;
            }
            // 再比較左邊
            while (num[index]>=num[left] && left<right){
                left++;
            }
            if (left<right){
                int temp = num[left];
                num[left] = num[right];
                num[right] = temp;
            }
        }

        // 交換基準元素
        int temp = num[index];
        num[index] = num[left];
        num[left] = temp;
        index = left;
        // 遞歸左區間
        sort(num,l,index-1);
        // 遞歸右區間
        sort(num,index+1,r);
 }

幾個常問的基礎排序就先分享到這了,喜歡的話關注我的個人微信公衆號,謝謝啦。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章