數據結構與算法——選擇排序和插入排序

1. 回顧

前面說到了冒泡排序,這是一種時間複雜度爲 O(n2) 、是原地排序和穩定的的排序算法,具體思路是:根據相鄰兩個元素之間比較大小,而後交換位置,得出最後排序的結果。具體可參考我寫的這一篇文章:數據結構與算法——冒泡排序,今天來看看另外兩種基礎的排序算法:選擇排序和插入排序。算法

2. 選擇排序

先來看看選擇排序,選擇排序的思路其實很簡單,將排序的數據分爲已排序區間和未排序區間,通常是以第一個元素爲已排序區間,而後依次遍歷未排序區間,找到其最小值,和未排序區間的最後一個值進行比較,交換位置。未排序區間遍歷完畢,則排序結束。光說可能有點抽象,我畫了一張圖來幫助你理解: segmentfault

在這裏插入圖片描述

是否是很簡單呢?下面是它的代碼實現:數組

public class SelectionSort {
    public static void selectionSort(int[] data){
        int length = data.length;
        //若是隻有一個元素,或者數組爲空,則直接退出
        if (length <= 1) return;

        for (int i = 0; i < length - 1; i++) {
            int min = i + 1;
            //找到最小值
            for (int j = i + 1; j < length; j++) {
                if (data[j] < data[min]) min = j;
            }
            //交換位置
            if (data[min] < data[i]){
                int temp = data[min];
                data[min] = data[i];
                data[i] = temp;
            }
        }
    }
}

結合代碼分析,選擇排序在最好、最壞和平均狀況下的時間複雜度都是 O(n2),而且沒有藉助額外的存儲空間,是一種原地排序算法。那麼選擇排序是穩定的嗎?答案是否認的,舉個例子:排序的數組爲 data[2, 2, 1, 3, 5, 4, 8],第一次遍歷未排序的數組,找到最小值爲 1,和第一個 2 交換位置,那麼這兩個 2 的先後順序就被打亂了,因此穩定性被破壞。正因如此,選擇排序比起冒泡排序和插入排序就顯得遜色不少了。數據結構

3. 插入排序

咱們再來看看插入排序,其實思路和上面的選擇排序很是的相似,也是將排序數據分爲已排序區間和未排序區間,依次遍歷未排序區間,和已排序區間的值進行比較,將其插入到合適的位置上,直至將未排序的區間數據遍歷完。spa

你能夠結合下面的圖來理解:3d

在這裏插入圖片描述

能夠看到,和選擇排序同樣,將第一個數據做爲已排序區間,第一次遍歷到 2 ,將其插入到 4 後面,而後再依次遍歷。
下面是代碼實現:code

public class InsertionSort {
    public static void insertionSort(int[] data){
        int length = data.length;
        if (length <= 1) return;

        for (int i = 1; i < length; i++) {
            int value = data[i];
            int j = i - 1;
            for (; j >= 0; j --){
                if (data[j] > value) data[j + 1] = data[j];
                else break;
            }
            data[j + 1] = value;
        }
    }
}

很顯然,插入排序也是穩定的,由於咱們是在 data[j] > da[j + 1] 的時候,才進行數據交換,不會影響到相同元素的先後位置。而且,插入排序是原地排序,最好狀況下,數組原本就是有序的,因此咱們只須要遍歷一次數組就能夠了,時間複雜度是 O(n),最壞狀況和平均狀況下,時間複雜度都是 O(n2)。blog

最後還有個問題,爲何在實際中,插入排序的比冒泡排序使用的更加普遍呢?雖然這兩個排序算法的平均時間複雜度都是 O(n2),可是結合代碼,不難發現,它們涉及到的數據交換操做時略有差異的。排序

冒泡排序在交換數據的時候,須要進行三次賦值操做,而插入排序只須要一次。圖片

//插入排序的賦值操做            
for (; j >= 0; j --){
    if (data[j] > value) data[j + 1] = data[j];
    else break;
}

//冒泡排序的賦值操做        
for (int j = 0; j < n - i - 1; j++) {
    //若是data[j] > data[j + 1],交換兩個數據的位置
    if (data[j] > data[j + 1]){
       int temp = data[j];
       data[j] = data[j + 1];
       data[j + 1] = temp;
    }

在數據規模小的時候,這樣的差異沒什麼影響,可是若是咱們要排序的是一組較大的數據,那麼兩種排序算法的執行時間的差異就會很明顯了。

相關文章
相關標籤/搜索