JS數據結構與算法 - 排序(冒泡、選擇、插入、歸併、快排)

🌸本文主要內容:javascript

時間複雜度

O(1) < O(logn) < O(n) < O(nlogn) < O(n²) < O(n³) < O(2^n) < O(n!) < O(n^n)java

js默認sort算法於各瀏覽器中的實現

冒泡排序O(n^2)

冒泡排序比較任何兩個相鄰的項,若是第一個比第二個大,則交換它們。元素項向上移動至正確的順序,就好像氣泡升至表面同樣,冒泡排序所以得名。算法

function bubbleSort(array) {
    let length = array.length
    for (let i = 0; i < length; i++) { //控制了在數組中通過多少輪排序
        for (let j = 0; j < length - 1 - i; j++) {
            if (array[j] > array[j + 1]) {
                let temp = array[j]
                array[j] = array[j + 1]
                array[j + 1] = temp
            }
        }
    }
    return array
}

選擇排序O(n^2)

選擇排序大體的思路是找到數據結構中的最小值並將其放置在第一位,接着找到第二小的值並將其放在第二位,以此類推。segmentfault

function selectSort(array) {
    let length = array.length
    let indexMin //記錄每次最小值所在的位置
    for (let i = 0; i < length; i++) {
        indexMin = i
        // 開始查找i以及i以後的最小值
        for (let j = i; j < length; j++) {
            if (array[indexMin] > array[j]) {
                indexMin = j
            }
        }
        if (i != indexMin) {
            let temp = array[i]
            array[i] = array[indexMin]
            array[indexMin] = temp
        }
    }
    return array
}

插入排序O(n^2)

插入排序每次排一個數組項,以此方式構建最後的排序數組。假定第一項已經排序了,接着,它和第二項進行比較,第二項是應該待在原位仍是插到第一項以前呢?這樣,頭兩項就已正確排序,接着和第三項比較(它是該插入到第1、第二仍是第三的位置呢?),以此類推。數組

function insertSort(array) {
    let length = array.length
    for (let i = 0; i < length; i++) {
        j = i
        temp = array[i]
        while (j > 0 && array[j - 1] > temp) {
            // 交換位置
            array[j] = array[j - 1]
            j--
        }
        array[j] = temp
    }
    return array
}

歸併排序O(nlogn)

歸併排序是第一個能夠被實際使用的排序算法。前三個排序算法性能很差,但歸併排序性能不錯,其複雜度爲O(nlogn)瀏覽器

歸併排序是一種分治算法。其思想是將原始數組切分紅較小的數組,直到每一個小數組只有一個位置,接着將小數組歸併成較大的數組,直到最後只有一個排序完畢的大數組。點擊查看歸併排序小動畫數據結構

// 建立
function Sort() {
    this.mergeSort = function (array) {
        return  mergeSortRec(array);
    };

    var mergeSortRec = function (item) {
        var length = item.length;
        if (length === 1) { //遞歸中止條件
            return item;
        }
        var mid = Math.floor(length / 2), //將數組分爲左右兩部分
            left = item.slice(0, mid),
            right = item.slice(mid, length);
        return merge(mergeSortRec(left), mergeSortRec(right));
    };

    // 負責合併和排序小數組來產生大數組
    var merge = function (left, right) {
        // console.log(left,right)
        var result = [],
            il = 0,
            ir = 0;
        //例子: [7,8],[5,6]
        while (il < left.length && ir < right.length) {
            if (left[il] < right[ir]) {
                result.push(left[il++]);
            } else {
                result.push(right[ir++]);
            }
        }
        while (il < left.length) {
            result.push(left[il++]);
        }
        while (ir < right.length) {
            result.push(right[ir++]);
        }
        // console.log(result)
        return result;
    };
}

// 使用
let sort = new Sort()
console.log(sort.mergeSort([2,3,4,5,2,1]))

快速排序O(nlogn)

快速排序也許是最經常使用的排序算法了。它的複雜度爲O(nlogn),且它的性能一般比其餘的複雜度爲O(nlogn)的排序算法要好。和歸併排序同樣,快速排序也使用分治的方法,將原始數組分爲較小的數組(但它沒有像歸併排序那樣將它們分割開)。函數

(1) 首先,從數組中選擇中間一項做爲主元。性能

(2) 建立兩個指針,左邊一個指向數組第一個項,右邊一個指向數組最後一個項。移動左指針直到咱們找到一個比主元大的元素,接着,移動右指針直到找到一個比主元小的元素,而後交換它們,重複這個過程,直到左指針超過了右指針。這個過程將使得比主元小的值都排在主元以前,比主元大的值都排在主元以後。這一步叫做劃分操做。動畫

(3) 接着,算法對劃分後的小數組(較主元小的值組成的子數組,以及較主元大的值組成的子數組)重複以前的兩個步驟,直至數組已徹底排序。

圖示:點擊可看大圖。或者點擊查看快速排序小動畫

// 建立
function Sort() {
    this.quickSort = function (array) {
        quick(array, 0, array.length - 1);
    };

    //聲明一個主方法來調用遞歸函數,傳遞待排序數組,以及索引0及其最末的位置(由於咱們要排整個數組,而不是一個子數組)做爲參數。
    var quick = function (item, left, right) {
        var index;
        if (item.length > 1) {
            index = partition(item, left, right); //index幫助將數組分離爲較小的和較大的數組
            if (left < index - 1) { //若是子數組存在較小值的元素
                quick(item, left, index - 1); //對該數組重複該過程
            }
            if (index < right) { //同理
                quick(item, index, right);
            }
        }
    };

    //劃分過程
    var partition = function (item, left, right) {
        var pivot = item[Math.floor((right + left) / 2)], //選擇主元(可隨機),這裏選擇中間值
            i = left,
            j = right;
        while (i <= j) { //只要左右指針沒有相互交錯,就執行劃分操做
            while (item[i] < pivot) { //移動left指針直到找到一個元素比主元大
                i++;
            }
            while (item[j] > pivot) { //移動right指針直到找到一個元素比主元小
                j--;
            }
            if (i <= j) { //左右指針沒有相互交錯
                swapQuickStort(item, i, j); //交換值
                i++; //繼續往下走
                j--;
            }
        }
        return i; //此刻順序 比主元小 主元 比主元大。返回分界指針到quick()相應語句中
    };

    var swapQuickStort = function (item, index1, index2) {
        var aux = item[index1];
        item[index1] = item[index2];
        item[index2] = aux;
    };
}

// 使用
let quickSort = new Sort()
let array = [4, 5, 1, 6, 2, 7, 3, 8]
quickSort.quickSort(array)
console.log(array)

推薦文章

Array.prototype.sort 各瀏覽器的算法實現

維基百科 - 排序算法(講解了各類排序算法,超多超詳)

選擇排序小動畫

冒泡排序小動畫

相關文章
相關標籤/搜索