常見排序算法基於JS的實現

一:冒泡排序算法

1. 原理shell

a. 從頭開始比較相鄰的兩個待排序元素,若是前面元素大於後面元素,就將二個元素位置互換編程

b. 這樣對序列的第0個元素到n-1個元素進行一次遍歷後,最大的一個元素就「沉」到序列的最後位置(第n-1個位置,n爲待排序元素個數)數組

c.排除這次排序最後面的那個元素(n=n-1),繼續對剩餘序列重複前面兩步瀏覽器

d. 當(n= n-1)=0時,排序完成app

2. 具體實現測試

以以下待排序序列爲例:ui

冒泡排序

到此,第一次冒泡完成,最大值7冒泡到最後面。spa

而後繼續對除最後元素(7)外的序列進行冒泡排序。具體實現以下:3d

/**
 * 冒泡排序
 * @param {Array} arr - 整型數組
 * @returns {Array} ret - 排好序的數組
 */

function bubbleSort(arr) {
    var n = arr.length,
        i = 0,
        temp;

    while(--n) {

        while (i < n) {

            // 若是前一個數大於後一個數,則互換位置
            if(arr[i] > arr[i+1]) {
                temp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = temp;
            }

            i++;
        }

        // 每次冒泡完成後,將i復位
        i = 0;
    }

    return arr;
}

// 基於qunit的測試
test('bubble-sort', function () {
    var arr1 = [6,2,4,3];
    var arr2 = [28,13,4,19,10];
    var arr3 = [2,3,2,4,2,5];

    propEqual(bubbleSort(arr1), [2,3,4,6]);
    propEqual(bubbleSort(arr2), [4,10,13,19,28]);
    propEqual(bubbleSort(arr3), [2,2,2,3,4,5]);
});

二:選擇排序

1. 原理

a. 首先在待排序序列中找到最小元素,放入儲存有序序列中。同時從待排序序列中刪除這個元素

b. 繼續從未排序序列中找到最小元素,而後a步中的有序列序列中

c. 以此類推,直到待排序序列元素個數爲0

2.  具體實現:

選擇排序

 

/**
 * 選擇排序
 * @param {Array} arr
 * @returns {Array} ret
 */
function selectionSort(arr) {
    var ret = [],
        min,
        i;

    while(arr.length) {

        // TODO 應該本身實現一個求數組中的最小值方法
        min  = Math.min.apply(null, arr);

        ret.push(min);

        // 從待排序數組中刪除這個元素
        arr.splice(arr.indexOf(min), 1);

    }

    return ret;
}

// qunit
test('selection-sort', function () {
    var arr1 = [1,5,3,6,4,2];
    var arr2 = [1,5,4,6,4,2];

    propEqual(selectionSort(arr1), [1,2,3,4,5,6]);
    propEqual(selectionSort(arr2), [1,2,4,4,5,6]);

});

三: 插入排序

1. 排序原理:

a. 從待排序序列第0個元素開始排序,該元素能夠認爲已是有序的

b. 取出下一個元素,在已經排序的元素序列中從後向左遍歷

c. 若是已排序元素大於新元素,將該元素移到下一位置

d. 重複步驟c,直到找到一個已排序的元素,此元素不大於新元素;或者元素位於有有序序列開始位置

e. 將新元素插入到此元素後面

f. 重複步驟b~e,直接待排元素個數爲0

 

2. 具體實現

插入排序 

/**
 * 插入排序
 * @param {Array} arr
 * @returns {Array} ret
 */
function insertionSort(arr) {

    // 從1開始,由於一個元素的序列,始終是有序的
    for(var i = 1, j; i < arr.length; i++) {

        j = i;

        // 保存待排序元素
        v= arr[j];

        // 若是有序序列中的元素大於待插入的元素,則有序列序列中的元素向後移動一個位置
        // 向後移到一個位置,會覆蓋待排序的元素,但咱們前面有保存待排序元素,因此待排序元素不會丟失
        // 同時,也留出一個位置,以插入待排序元素
        // 直到找一個已經排序的元素,其不大於待排序元素,將待排序元素插入到這裏。
        // 若是遍歷到有序序列的開始位置,也不存在一個元素不大於待排序元素,則將待排序元素插入到已經排序序列的開始

        while(arr[j-1] > v) {
            arr[j] = arr[j-1];
            j--;

            if(j === 0) {
                break;
            }
        }

        arr[j] = v;
    }

    return arr;
}

// qunit
test('insertion-sort', function () {
    var arr1 = [1,5,3,6,4,2];
    var arr2 = [1,5,4,6,4,2];

    propEqual(insertionSort(arr1), [1,2,3,4,5,6]);
    propEqual(insertionSort(arr2), [1,2,4,4,5,6]);

});

四:希爾排序

1.  排序原理:

a. 設定一個間距d,將待排序序列分組

b. 對分組使用插入排序

c. 改變d, 再次分組

d. 再次對上面的分組使用插入排序

e. 重複上面的步驟,直至d爲1,並進行最後一次插入排序,獲得排好序的序列

 

2. 具體實現

希爾排序1

希爾排序2

希爾排序過程當中,涉及到選擇一組間距序列,這個序列叫叫希爾增量。希爾增量的奧妙之後有時間再研究。

/**
 * 希爾排序
 * @param {Array} arr
 * @returns {Array}
 */
function shellSort(arr) {

    // 動態取得一個希爾增量

    var N = arr.length;
    var h = 1;

    var i, j, v;

    // 產生希爾增量序列第一個值
    while (h < N / 3) {
        h = 3 * h + 1; //
    }

    // 對分組使用插入排序,同時改變希爾增量值,直到其爲1,並進行最後一次插入排序,獲得有序序列
    // 第一次插入排序,都是能夠將待排序序列排成有序序列的
    // 不停運用插入排序,實際上是減小了元素在排序過程當中移動的次數
    while (h >= 1) {
        for (i = 1; i < arr.length; i++) {

            j = i;
            v = arr[j];

            while (j > 0 && arr[j - 1] > v) {
                arr[j] = arr[j - 1];
                j--;
            }

            arr[j] = v;
        }

        h = (h - 1) / 3; // 從①能夠保證,確定能除盡的
    }

    return arr;
}

// qunit
test('shell-sort', function () {
    var arr1 = [1,5,3,6,4,2,22,34,11,12,45];
    var arr2 = [1,5,4,6,4,2];

    propEqual(shellSort(arr1), [1,2,3,4,5,6,11,12,22,34,45]);
    propEqual(shellSort(arr2), [1,2,4,4,5,6]);

});

五. 歸併排序

1. 排序原理:

歸併排序主要分兩步:

a. 分組

對待排序序列按二分法分紅兩個小序列,並一直遞歸下去,直到序列長度爲1(長度爲1 的序列是有序的)

b. 合併

將排好序的數組合併成有序數列,最後獲得排序結果

2. 具體實現

歸併排序1

歸併排序2

// 歸併排序
function mergetSort(arr) {

    if(arr.length === 1) {
        return arr;
    }

    var leftArr = arr.slice(0, Math.floor(arr.length / 2));
    var rightArr = arr.slice(leftArr.length);

    // 遞歸
    return merge(mergetSort(leftArr), mergetSort(rightArr));

    // 合併有序序列
    function merge(arrLeft, arrRight) {

        var indexLeft = 0,
            indexRight = 0,
            sl = arrLeft.length,
            sr = arrRight.length,
            ret = [];


        while(true) {
            if(indexLeft < sl && indexRight < sr) {
                if(arrLeft[indexLeft] < arrRight[indexRight]) {
                    ret.push(arrLeft[indexLeft]);
                    indexLeft++;
                } else {
                    ret.push(arrRight[indexRight]);
                    indexRight++;
                }
            } else {
                if(indexLeft < indexRight) {
                    ret = ret.concat(arrLeft.slice(indexLeft));
                } else {
                    ret = ret.concat(arrRight.slice(indexRight));
                }
                break;
            }
        }

        return ret;
    }

}

// qunit
test('merge-sort', function () {
    var arr1 = [28,13,4,19,10];
    var arr2 = [1,5,4,6,4,2];

    propEqual(mergetSort(arr1), [4,10,13,19,28]);
    propEqual(mergetSort(arr2), [1,2,4,4,5,6]);
});

六: 快速排序

1. 排序原理

a. 從序列中挑出一個元素,稱爲 "基準"(pivot),

b. 從新排序序列,全部元素比基準值小的元素擺放在基準前面,全部元素比基準值大的擺在基準後面

c. 把新獲得的序列再經過上面的方法排序。當序列長度爲1或0時結束遞歸

2. 具體實現

快速排序

// 快速排序
function quickSort(arr) {
    var pivot = arr[0];
    var i = 1;
    var leftArr= [],
        rightArr = [];

    if(arr.length === 0) {
        return [];
    }

    if(arr.length === 1) {
        return arr;
    }

    for(; i < arr.length; i++) {
        if(arr[i] < pivot) {
            leftArr.push(arr[i]);
        } else {
            rightArr.push(arr[i]);
        }
    }

    return quickSort(leftArr).concat(pivot, quickSort(rightArr));
}

// qunit
test('quick-sort', function () {
    var arr1 = [6,2,4,3];
    var arr2 = [28,13,4,19,10];
    var arr3 = [4,1,7,3,5,2,6];

    propEqual((quickSort(arr1)), [2,3,4,6]);
    propEqual(quickSort(arr2), [4,10,13,19,28]);
    propEqual(quickSort(arr3), [1,2,3,4,5,6,7]);
});


小結:

本文把常見的排序算法(冒泡,選擇,插入,希爾,歸併,快速排序)基於JS實現了一遍,練習一下算法,仍是有助於提升編程思惟的。好比求一個數組的最大值。咱們知道能夠這樣:

var max = Math.min.applu(null, arr)

可是瀏覽器內部是怎麼實現的呢,又或者假設瀏覽器沒提供這個方法,咱們本身怎麼作呢?其實經過一次向左冒泡就能夠獲得最小值:

function getMinValue(arr) {
    var i = arr.length, j;

    j = i;

    while(--j) {
        if(arr[j - 1] > arr[j]) {
            arr[j - 1] = [arr[j - 1], arr[j]];
            arr[j] = arr[j - 1][0];
            arr[j- 1] = arr[j - 1][1];
        }
    }

    // 返回最小值
    return arr[0];
}
相關文章
相關標籤/搜索