邏輯之美(2)_選擇排序

開篇

上篇咱們好好聊了聊冒泡排序,這篇咱們來聊聊另外一種初級排序算法——選擇排序java

正文

選擇排序的算法思路一樣很簡單。仍是數組爲例,咱們如今有個整數數組,要求將其中整數元素按值的大小從小到大排個序。選擇排序的具體思路是這樣:先從頭遍歷數組,找出其中值最小的那個元素,而後將其值同遍歷區間最開始那個元素交換,若是值最小的元素恰是最開始那個元素,就本身跟本身交換值。第一遍遍歷完成,數組中最小的值已是數組第一個元素,此時數組第一個元素已部分有序,將從新遍歷的初始下標加一,開始下次遍歷,如此循環,直至遍歷區間內只剩一個元素,此時數組已總體有序。算法

來具象化捋一遍選擇排序的邏輯:數組

``函數

設現有無序數組 a = [40, 50, 20, 30, 10]
    其有序狀態應爲 a = [10, 20, 30, 40, 50]
    咱們對其作下選擇排序,具象展現以下:
數組下標:a[0]  a[1]  a[2]  a[3]  a[4]
初始值: 40   50   20    30   10  

第一次選擇遍歷過程: 40   50   20   30   10  (遍歷區間值最小元素爲a[4],
                    ↑                   ↑  與遍歷區間初始下標a[0]交換值)
                   
第二次選擇遍歷過程: 10   50   20   30   40  (最小元素爲a[2],與a[1]交換值,
                   ---   ↑    ↑                 下劃線標示的元素已部分有序)

第三次選擇遍歷過程: 10   20   50   30   40  (最小元素爲a[3],與a[2]交換值,
                   --------   ↑    ↑          下劃線標示的元素已部分有序)
                   
第四次選擇遍歷過程: 10   20   30   50   40  (最小元素爲a[4],與a[3]交換值,
                   ------------    ↑    ↑   下劃線標示的元素已部分有序)
                   
第五次選擇遍歷過程: 10   20   30   40   50  (遍歷區間內只剩一個元素了,
                   ------------------  ↑↑   代表此時數組已總體有序)
                   
數組此時已總體有序: 10   20   30   40   50  (數組此時已總體有序)
                   -----------------------
複製代碼

OK 邏輯捋的差很少了咱們開始擼代碼,以 Java 爲例,咱們先來擼個爲整數數組選擇排序的遞歸實現版本:post

/** * @see: 選擇排序的遞歸實現 * @param array: 待排序數組,咱們採用原地排序 * @param start: 當次查找最小值(遍歷區間)的初始下標,初次調用值應爲0 */
    public static void sortSelect(int[] array, int start){
        //遞歸結束條件,此時數組已總體有序
        if (start >= array.length - 1){
            return;
        }

        //先假定遍歷區間第一個下標的值爲最小值;
        int minValueIndex = start;
        //開始遍歷特定數組區間,將區間內最小值交換到區間初始位置
        for (int i = start + 1; i <= array.length - 1; i ++){
            if (array[i] < array[minValueIndex]){
                minValueIndex = i;
            }
        }
        //把最小的值交換到遍歷區間初始下標位置
        int mid = array[start];
        array[start] = array[minValueIndex];
        array[minValueIndex] = mid;
        //遞歸開始遍歷下個遍歷區間
        sortSelect(array, start + 1);
    }
複製代碼

咱們在實際生產環境中寫排序算法確定不能用遞歸,在 Java 中遞歸的函數調用棧太深會致開銷甚大,上面主要是爲便於理解來的初級版本,咱們來優化成非遞歸版本,即雙層嵌套版本:優化

/** * @see: 選擇排序的非遞歸實現,即雙層嵌套實現 * @param array: 待排序數組,咱們採用原地排序 */
    public static void sortSelect(int[] array){
        //遞歸結束條件,此時數組已總體有序
        for (int start = 0; start < array.length - 1; start ++){
            //先假定遍歷區間第一個下標的值爲最小值;
            int minValueIndex = start;
            for (int startInner = start + 1; startInner <= array.length - 1; startInner ++ ){
                if (array[startInner] < array[minValueIndex]){
                    minValueIndex = startInner;
                }
            }
            //把最小的值交換到遍歷區間初始下標位置
            int mid = array[start];
            array[start] = array[minValueIndex];
            array[minValueIndex] = mid;
            //循環開始遍歷下個遍歷區間
        }
    }
複製代碼

兩種實現代碼擼下來,相信你已完全掌握了選擇排序算法。spa

尾巴

選擇排序有兩個特色:code

  1. 運行時間和輸入無關,其時間複雜度恆爲 О(n²),即便你輸入的數組原本就總體有序也是如此!
  2. 數據值交換(或言數據移動)是最少的,如上所示,一次遍歷只有一次值交換,還有多是本身跟本身交換,對比冒泡排序,你知道我在說什麼!

選擇排序須要的額外空間複雜度同冒泡排序,爲О(1)排序

讀者請自行發散思惟把以上代碼改爲爲 Comparable 數組排序的版本。遞歸

下篇咱們聊插入排序。

完。

相關文章
相關標籤/搜索