排序算法複習:直接插入排序、堆排序、快排、冒泡排序

這裏有動態圖示,效果很好:https://www.toptal.com/developers/sorting-algorithms/算法

冒泡排序,感受是最簡單的排序:數組

基本思路:每次把數組中最小的一個元素像氣泡同樣浮動、固定到最頂端:dom

  從前向後遍歷數組,每次拿到一個元素,就執行一遍冒泡:ide

    從數組末尾開始,到當前元素截止,從後向前遍歷,每次比較數組中相鄰的兩個元素,若是後者比較小,就把二者互換。函數

  

  這樣通過第一次冒泡,能夠把最小的元素『浮』到數組的首位。第二次冒泡會把第二小的元素『浮』到數組的第二位。直到全部的元素都被『浮動』到正確的位置。測試

代碼極其簡單:ui

var BubbleSort = function (array) {
    var len = array.length;
    for(var i=0; i<len; ++i){
        for(var j=len-1; j>i; --j){
            if(array[j] < array[j-1]){
                var temp = array[j];
                array[j] = array[j-1];
                array[j-1] = temp;
            }
        }
    }
};
View Code

冒泡算法通常是把小的元素上浮。也能夠略微改動一下,變成大的元素下沉,實現上很類似。spa

 

插入排序:code

基本思路:假定已有一個有序數組(從小到大),則每次插入只要把新元素放到合適的位置就能夠了,爲了減小額外的內存佔用,能夠在原數組上作調整:blog

  對數組從前向後遍歷,保證遍歷過的元素,都是從小到大排列:因此遍歷到新元素時,就要把新元素和已遍歷過的元素逐個比較,經過 swap 最後把新元素放到合適位置。

代碼實現:

var InsertSort = function (array) {
    //從前到後,每次指定一個數字,逐個比較它以前的每一個數字,插入到合適的位置
    var len = array.length;
    for(var i=0; i<len; ++i){
        for(var j=i; j>0; --j){
            if(array[j] < array[j-1]){
                var tmp = array[j - 1];
                array[j - 1] = array[j];
                array[j] = tmp;
            }
            else {
                break;
            }
        }
    }
};
View Code

感受直接插入排序,中間也有用到冒泡的思路:遍歷到新元素時,用冒泡的方式,把新元素逐步浮動到正確的位置。

 

 

堆排序:

基本思路:構建一個最小堆,每次從堆中取出堆頂,也就是最小元素。而後調整最小堆,再次取出堆頂的最小元素。直到堆爲空。(用數組的方式構建優先隊列的方式,我後續寫一下)

  爲了不申請額外的數組,此處直接在原數組中作了調整:每次取出的最小元素沒有放到新的數組,而是放到數組尾部,而後把剩下的數組元素調整成最小堆。

  這樣當全部元素都被移動到數組尾端以後,也就完成了排序。

代碼實現:

//從小到大
var HeapSort  = function (array) {
    var len = array.length;
    for(var k=len-1; k>=0; --k) {
        //build heap
        for (var i = k; i > 0; --i) {
            var pIndex = Math.floor((i - 1) / 2);
            if (array[i] < array[pIndex]) {
                var temp = array[pIndex];
                array[pIndex] = array[i];
                array[i] = temp;
            }
        }

        //remove smallest to array end
        array.push(array.shift());
    }
};
View Code

這裏用到了 JS 中的數組內建函數 shift、push。若是要更通用的方式,有這樣一個思路:第一次構建成最小堆後,不取出堆頂,而是直接用除堆頂之外的元素再次構建最小堆。僞碼以下:

for(i from 0 to array.lengh){

  build heap using array[i]-array[length-1]

}

 

 

快排:

  據論證是最快的排序方式,等後續我實現希爾排序後比較一下速度。。。

基本思路:每次指定一個元素,將數組中全部小於它的元素,放到數組最側,大於它的元素放到右側。而後以該元素爲界分紅兩個數組區間,對它們執行一樣的操做。

代碼實現:

var QuickSort = function (array, pre, last) {
    var keyIndex = last;
    var key = array[keyIndex];

    var oldPre = pre;
    var oldLast = last;

    last -= 1;
    if(pre > last){
        return;
    }

    while(pre <= last){
        if(array[pre] <= key){
            ++pre;
        }
        else if(array[last] >= key){
            --last;
        }
        else {
            var temp = array[last];
            array[last] = array[pre];
            array[pre] = temp;
        }
    }
    array[keyIndex] = array[pre];
    array[pre] = key;

    QuickSort(array, oldPre, pre-1);
    QuickSort(array, pre+1, oldLast);
};
View Code

 

JS 中數組的 sort 函數,也是用的快排,可是我對比後發現 sort 函數比上面實現的快排要慢,基本上 sort 耗時是 QuickSort 的2-3倍。這中間具體多了些什麼?

用來對比的 sort 函數:

arrayCopy.sort(function (first, second) {
    if(first < second){
        return -1;
    }
    return 1;
});
View Code

 

附上個人測試代碼:

var testArray = [];
var totalNum = 20000;
for(var i=0; i<totalNum; ++i){
    testArray.push(Math.random() * totalNum);
    // testArray.push(Math.ceil(Math.random() * totalNum));
}

var arrayCopy = testArray.slice();
var now = Date.now();
InsertSort(arrayCopy);
console.log("插入排序:" + (Date.now() - now));

arrayCopy = testArray.slice();
now = Date.now();
HeapSort(arrayCopy);
console.log("堆排序:" + (Date.now() - now));

arrayCopy = testArray.slice();
now = Date.now();
BubbleSort(arrayCopy);
console.log("冒泡排序:" + (Date.now() - now));

arrayCopy = testArray.slice();
now = Date.now();
arrayCopy.sort(function (first, second) {
    if(first < second){
        return -1;
    }
    return 1;
});
console.log("Array.sort 排序:" + (Date.now() - now));

arrayCopy = testArray.slice();
now = Date.now();
QuickSort(arrayCopy, 0, arrayCopy.length-1);
console.log("快排:" + (Date.now() - now));
View Code

幾回測試的結果:

插入排序:217
堆排序:770
冒泡排序:740
Array.sort 排序:11
快排:6


插入排序:217
堆排序:771
冒泡排序:753
Array.sort 排序:10
快排:5


插入排序:218
堆排序:763
冒泡排序:735
Array.sort 排序:9
快排:4


插入排序:217
堆排序:762
冒泡排序:747
Array.sort 排序:11
快排:7


插入排序:222
堆排序:764
冒泡排序:759
Array.sort 排序:17
快排:7
View Code
相關文章
相關標籤/搜索