基本排序演算法

chen4342024發表於2019-02-16

基本排序演算法

在電腦科學中,一個排序演算法是一種能將一串資料依照特定的排列方式進行排列的一種演算法。

這裡簡單的介紹三種最基本的排序,分別是:氣泡排序、選擇排序以及插入排序

排序的過程中,經常要用到交換元素位置,故抽離為公共函式 swap

// 交換位置
export function swap(arr, index1, index2) {
    var temp = arr[index1];
    arr[index1] = arr[index2];
    arr[index2] = temp;
}

氣泡排序

氣泡排序是最簡單的排序,一一對比相鄰的兩個數,順序不對就交換過來,這樣子,每一輪最大的值總會慢慢的被交換到最右側。所以才會叫氣泡排序

描述

假設陣列長度為 n

  • 比較相鄰的兩個數,如果第 1 個大於第 2 個,就交換位置
  • 重複第 1 步,一輪下來最大值被交換到第 n 個位置,也就是最右側
  • 開啟新一輪,重複 1~2 步,最大值會被冒泡到第 n-1 個位置
  • 重複上述步驟,直到所有都排序好

例子:

對 3, 1, 5, 2, 4 進行排序

1,3,5,2,4  3 > 1 ,交換位置
1,3,5,2,4  3 < 5 ,不變
1,3,2,5,4  5 > 2 ,交換位置
1,3,2,4,5  5 > 4 ,交換位置,第一輪結束
1,3,2,4,5  1 < 3 ,不變
1,2,3,4,5  3 > 2 ,交換位置
1,2,3,4,5  ...依次對比
1,2,3,4,5  ...
1,2,3,4,5  ... 結束

程式碼實現

// 氣泡排序
export function bubbleSort(array) {
    for (let i = array.length - 1; i >= 1; i--) {
        let hasSwap = false;
        for (let j = 0; j <= i; j++) {
            if (array[j] > array[j + 1]) {
                swap(array, j, j + 1);
                hasSwap = true;
            }
        }
        if (!hasSwap) {
            // 這裡用於優化,如果某一輪之後,沒有進行任何交換,說明已經排序完成了,所以退出迴圈
            break;
        }
    }
}

效果演示

https://global.chen4342024.co…

注意開啟開發者工具,切換到移動端模式

小結

冒泡演算法是比較慢的排序之一,也是最容易實現的演算法之一。

複雜度
  • 穩定性:穩定
  • 時間複雜度: 平均 O(n^2) 、 最壞 O(n^2) 、最好 O(n)
  • 額外空間複雜度 O(1)

選擇排序

選擇排序是指每一輪從陣列中取出最小值,然後跟第一個元素交換位置。然後再找出第二個最小值,跟第二個元素交換位置,。。。以此類推。直到倒數第二個位置

例子

3, 1, 5, 2, 4 進行排序

// 這裡只展示每一輪的結果
3 1 5 2 4   //開始
1 3 5 2 4   //第 1 輪
1 2 5 3 4   //第 2 輪
1 2 3 5 4   //第 3 輪
1 2 3 4 5   //第 4 輪

程式碼實現

// 選擇排序從開頭開始,找出最小的值,放在第一個位置
// 有點類似打撲克拍的時候,抽取每一張最小的放在最左邊
export function selectSort(array) {
    for (let i = 0; i < array.length - 1; i++) {
        let minIndex = i;
        let min = array[i];
        for (let j = i + 1; j < array.length; j++) {
            if (array[j] < min) {
                min = array[j];
                minIndex = j;
            }
        }
        swap(array, i, minIndex);
    }
}

效果演示

https://global.chen4342024.co…

注意開啟開發者工具,切換到移動端模式

複雜度
  • 穩定性:不穩定
  • 時間複雜度: O(n^2)
  • 額外空間複雜度 O(1)

插入排序

插入排序的思想是,依次從陣列中未排序的部分,取出資料,然後插入到已排序的部分。直到清空未排序的部分

描述

假設陣列長度為 n , 從第 2 項開始

  • 從第一個元素開始,該元素可以認為已經被排序;
  • 取出下一個元素,在已經排序的元素序列中從後向前掃描;
  • 如果該元素大於新元素,將該元素移到下一位置;
  • 重複步驟 3,直到找到已排序的元素小於或者等於新元素的位置;
  • 將新元素插入到該位置後;
  • 重複步驟 2~5。

程式碼實現

export function insertSort(array) {
    for (let i = 0; i < array.length; i++) {
        let temp = array[i];
        let j = i;
        while (j > 0 && array[j - 1] > temp) {
            // 將所有大於temp的往右移
            array[j] = array[j - 1];
            j--;
        }
        array[j] = temp;
    }
}

效果演示

https://global.chen4342024.co…

注意開啟開發者工具,切換到移動端模式

複雜度
  • 穩定性:穩定
  • 時間複雜度:平均 O(n^2) 、 最壞 O(n^2) 、最好 O(n)
  • 額外空間複雜度 O(1)

效果演示(彙總)

https://global.chen4342024.co…

注意開啟開發者工具,切換到移動端模式

總結

這三種最基本的排序演算法的複雜度非常相似,從理論上來說,它們的執行效率也應該差不多。

在實際使用中,如果需要排序的資料比較多,是不推薦使用這 3 種排序的。畢竟他們的效率都不太理想

在實際應用中,應該選擇高階排序演算法: 快速排序 …

在隨機生成資料測試的時候,發現很多時候,插入排序要快於氣泡排序以及選擇排序。大概是冒泡/選擇排序的快 1 倍

這是因為 插入排序需要比較的次數是 1+2+3+..+n = n * (n-1) /2,這是最壞的情況,大部分時候並不需要全部比較,所以平均下來只需要 n*(n-1)/4

而冒泡/選擇排序都需要n * (n-1)/2,所以平均下來,插入排序大概是冒泡/選擇排序的快 1 倍

相關文章