記一次冒泡、插入、歸併排序的時間比較

正文

直入正題javascript

兩個關鍵變量java

size:產生的隨機數組的長度,隨機數組中的每一項爲 Math.round(1000 * Math.random())數組

n:實驗的次數dom

結論:spa

  • 冒泡排序:弟中弟
  • 插入排序:相對弟弟
  • 歸併排序:大家都是弟弟

n = 50000 size = 100的狀況下code

n(次數) size(隨機數組的長度) 冒泡排序(s) 插入排序(s) 歸併排序(s)
10 5000 0.568 0.272 0.019
10 10000 2.531 1.347 0.029
10 50000 77.843 32.226 0.168
10000 50 1.975 0.082 0.182
25000 50 4.881 0.226 0.455
50000 50 10.31 0.363 0.895

關於這個結論,歸併排序沒什麼好說的,在o(n)的空間複雜度消耗下,其o(nlogn)的時間複雜度確實使它的排序速度最快,並且n(nlogn)真的比o(n^2)快太多了。然而,其中有一點使人奇怪:當n比較大,size比較小的時候,歸併排序的時間甚至比不過插入排序。對象

我我的的想法是:排序

  • size越大,生成數組徹底無序的可能性就越高,使得插入排序的時間複雜度接近O(n^2),致使其時間變得愈來愈接近冒泡排序。
  • size越小,生成數組徹底有序或局部有序的可能性就越高,使得插入排序的時間複雜度接近O(n),比起歸併的o(nlogn)要小,所以所用的時間比歸併少。

實驗代碼

可直接粘貼運行ip

const makeRandomArr = exports.makeRandomArr = size => {
    return Array(size).fill(null).map(() => Math.round(Math.random() * 1000));
};

const bubSort = exports.bubSort = arr => {
    if (arr == null) return arr;
    for (let round = 0; round < arr.length; round++) { // round每一輪
        for (let target = 0; target < arr.length - 1 - round; target++) { //target當前比較對象
            if (arr[target] > arr[target + 1])
                [ arr[target], arr[target + 1] ] = [ arr[target + 1], arr[target] ];
        }
    }
}

const insSort = exports.insSort = arr => {
    if (arr == null) return arr;
    for(let nextSort = 1; nextSort < arr.length; nextSort++) {
        for (let sorted = nextSort - 1; sorted > -1; sorted--) {
            if (arr[sorted + 1] < arr[sorted]) [ arr[sorted + 1], arr[sorted] ] = [ arr[sorted], arr[sorted + 1] ];
            else break;
        }
    }
}

const mergeSort = exports.mergeSort = arr => {
    const merge = (arr, l, mid, r) => {
        let p1 = l;
        let p2 = mid + 1;
        let helpOffset = 0;
        let helpArr = Array(r - l + 1);
        while(p1 <= mid && p2 <= r) {
            if (arr[p1] <= arr[p2]) {
                helpArr[helpOffset++] = arr[p1++];
            } else {
                helpArr[helpOffset++] = arr[p2++];
            }
        }

        while (p1 <= mid) {
            helpArr[helpOffset++] = arr[p1++];
        }

        while (p2 <= r) {
            helpArr[helpOffset++] = arr[p2++];
        }

        for (let offset = 0; offset < helpArr.length; offset++) {
            arr[l + offset] = helpArr[offset];
        }
    }
    const innerMergeSort = (arr, l, r) => {
        if (l === r) return;
        // console.log('l r', l, r);

        const mid = Math.floor((l + r) / 2);
        // console.log('mid', mid);
        innerMergeSort(arr, l, mid);
        innerMergeSort(arr, mid + 1, r);
        merge(arr, l, mid, r);
    }
    innerMergeSort(arr, 0, arr.length - 1);
}


(function main() {
    
    let sum = 0;
    let sum2 = 0;
    let sum3 = 0;

    let n = 10;
    let size = 1000000;

    for (let i = 0; i < n; i++) {
        let arr = makeRandomArr(size);
        let anothrArr = arr.slice();

        let t1 = new Date();
        console.time('bub'+i);

        bubSort(arr);

        console.timeEnd('bub'+i);
        let t2 = new Date()
        sum += t2 - t1;

        let t3 = new Date();
        console.time('ins'+i);

        insSort(anothrArr);

        let t4 = new Date();
        sum2 += t4 - t3;
        console.timeEnd('ins'+i);

        let t5 = new Date();
        console.time('merge'+i);

        mergeSort(anothrArr);

        let t6 = new Date();
        sum3 += t6 - t5;
        console.timeEnd('merge'+i);
    }
    console.log(`sum: ${sum / 1000}s, sum2: ${sum2 / 1000}s, sum3: ${sum3 / 1000}s`);
})();
複製代碼
相關文章
相關標籤/搜索