1. 程式人生 > 其它 >幾種常見排序演算法的實現及執行時間對比

幾種常見排序演算法的實現及執行時間對比

技術標籤:演算法

// 氣泡排序
function popSort(arr) {
    if (arr.length < 2) return arr;
    let n = arr.length;
    while (n > 1) {
        let exchanged = false;
        for (let i = 0; i < n - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                exchange(arr, i, i + 1);
                exchanged = true;
            }
        }
        n--;
        if (!exchanged) break;
    }
    return arr;
}
//插入排序
function insertSort(arr) {
    if (arr.length < 2) return arr;
    let n = 1;
    while (n < arr.length) {
        let val = arr[n];
        let i = n-1;
        for (; i>= 0; i--) {
            let prev = arr[i];
            if (val<prev) {
                arr[i+1] = arr[i]
            }else {
                break;
            }
        }
        arr[i+1] = val;
        n++;
    }
    return arr;
}

//希爾排序
function shellSort(arr){
    if (arr.length < 2) return arr;
    let n = arr.length;
    let h = 1;
    while(h<n/3)h=(h+1)*2-1;//Hibbard增量
    while(h>=1){
        for(let i = h;i<n;i++){
            for(let j = i; j>=h && arr[j]<arr[j-h];j-=h){
                exchange(arr,j,j-h);
            }
        }
        h = (h+1)/2-1;
    }
    return arr;
}

//歸併排序
function mergeSort(arr){
    if (arr.length < 2) return arr;
    merge_sort(arr,0,arr.length-1);
    function merge_sort(arr,l,r){
        if(l>=r)return;
        let mid = Math.floor((r-l)/2)+l;
        merge_sort(arr,l,mid);
        merge_sort(arr,mid+1,r);
        merge(arr,l,r,mid);
    }
    function merge(arr,l,r,mid){
        let arrcopy = [];
        let leftIndex = l, rightIndex = mid+1;
        for(let i = l; i<=r;i++){
            arrcopy[i] = arr[i];
        }
        for(let i = l; i<=r;i++){
            if(leftIndex>mid){
                arr[i] = arrcopy[rightIndex++]
            }else if(rightIndex>r){
                arr[i] = arrcopy[leftIndex++]
            }else if(arrcopy[leftIndex] <= arrcopy[rightIndex]){
                arr[i] = arrcopy[leftIndex++];
            }else{
                arr[i] = arrcopy[rightIndex++];
            }
        }
    }
}

//快速排序
function quickSort(arr){
    if (arr.length < 2) return arr;
    sort(arr,0,arr.length-1);
    function partition(arr,l,r){
        let i = l, j = r+1;
        let v = arr[l];
        while(true){
            while(arr[++i] <= v) if(i === r)break;
            while(arr[--j] >= v) if(j === l)break;
            if(i>=j)break;
            exchange(arr,i,j);
        }
        exchange(arr,l,j);
        return j;
    }
    function sort(arr,l,r){
        if(l>=r) return;
        let j = partition(arr,l,r);
        sort(arr,l,j);
        sort(arr,j+1,r);
    }
}
function exchange(arr, i, j) {
    [arr[i], arr[j]] = [arr[j], arr[i]]
}
function generateRandomArr(n, range) {
    const numberRange = range || 1000;
    const res = [];
    while (n-- > 0) {
        res.push(Math.round((Math.random() - 0.5) * numberRange));
    }
    return res;
}
//判斷陣列是否是升序的 O(n)
function isASC(arr) {
    let n = arr.length - 1;
    while (n > 0) {
        if (arr[n] < arr[n - 1]) return false;
        n--;
    }
    return true;
}
function printUsedTime(func) {
    let timestamp = new Date().getTime();
    func();
    console.log((new Date().getTime() - timestamp)+'ms');
}

let arrlength = 200000,arrRange = 20000;
console.log(`被排序陣列大小:${arrlength},陣列元素取值範圍:-${arrRange/2}到+${arrRange/2}`)
let arr1 = generateRandomArr(arrlength, arrRange);
let arr2 = generateRandomArr(arrlength, arrRange);
let arr3 = generateRandomArr(arrlength, arrRange);
let arr4 = generateRandomArr(arrlength, arrRange);
let arr5 = generateRandomArr(arrlength, arrRange);
console.log("pop sort")
printUsedTime(() => {
    popSort(arr1);
    console.log(isASC(arr1) ? "升序" : "無序");
})

console.log("insert sort")
printUsedTime(() => {
    insertSort(arr2);
    console.log(isASC(arr2) ? "升序" : "無序");
})

console.log("shell sort")
printUsedTime(() => {
    shellSort(arr3);
    console.log(isASC(arr3) ? "升序" : "無序");
})

console.log("merge sort")
printUsedTime(() => {
    mergeSort(arr4);
    console.log(isASC(arr4) ? "升序" : "無序");
})

console.log("quick sort")
printUsedTime(() => {
    quickSort(arr5);
    console.log(isASC(arr5) ? "升序" : "無序");
})
// console.log(isASC([1,-1,0,50,-50]) ? "升序" : "無序")

用大小為200000的陣列測試各個排序的執行時間消耗,結果如下:

被排序陣列大小:200000,陣列元素取值範圍:-10000到+10000

pop sort
升序
88375ms

insert sort
升序
8609ms

shell sort
升序
52ms

merge sort
升序
998ms

quick sort
升序
29ms

其中mergeSort,shellSort,quickSort都是時間複雜度為O(nLogn)的演算法,為啥mergeSort這麼慢呢?猜測可能是因為消耗的記憶體空間相對更多,有更多的資料搬移操作導致的耗時劇增。