快排

寫這篇文章源於以前的一次面試以及網上看到各類說原生的sort比快排快的例子,由於他們都沒有寫好快排。面試的時候讓我寫一個快排,我寫出了我在網上看的的很簡潔的一段代碼(後來發現這個代碼在數據結構和算法JavaScript描述這本書上也有):面試

function quickSort(arr){
    if(arr.length < 1){
            return [];
    }
    var left = [],right = [],flag = arr[0];
    for(var i=1;i<arr.length;i++){
        if(arr[i] <= flag){
            left.push(arr[i]);
        }else{
            right.push(arr[i]);
        }
    }
    return quickSort(left).concat(flag,quickSort(right));
}

這樣寫的話,乍一看確實是快排的思想,把比主元小的元素放到左數組,把比主元大的元素放到右數組,而後分別對左右數組的元素進行排序最終拼接成新的數組。
可是計算機課程裏講解快排的時候都不是這樣講解的,一趟快速排序的算法通常是這樣講解的:算法

  1. 設置兩個變量i、j,排序開始的時候:i=0,j=N-1;
  2. 以第一個數組元素做爲關鍵數據,賦值給key,即key=A[0];
  3. 從j開始向前搜索,即由後開始向前搜索(j--),找到第一個小於key的值A[j],將A[j]和A[i]互換;
  4. 從i開始向後搜索,即由前開始向後搜索(i++),找到第一個大於key的A[i],將A[i]和A[j]互換;
  5. 重複第三、4步,直到i=j;

採用js實現的版本以下:chrome

function quickSort_two(arr){
    function sort(start,end){
        if(start + 1 > end){
            return;
        }
        var flag = arr[start],f = start,l = end;
        while(f < l){
            while(f < l && arr[l] > flag){
                l--;
            }
            arr[f] = arr[l];
            while(f < l && arr[f] <= flag){
                f++;
            }
            arr[l] = arr[f];
        }
        arr[f] = flag;
        sort(start,f-1);
        sort(f+1,end);   
    }
    sort(0,arr.length-1);
}

對比這兩中快排的寫法,在時間複雜度上都是O(nlogn),可是第二種寫法使用了更少的空間,第一種寫法的空間複雜度是O(nlogn),而第二種的空間複雜度是O(logn),並且對數組的操做都在原數組上進行,減去了建立空間的消耗和時間,在性能上無疑有了更多的提高。數組


下面是三種排序算法的一個對比:數據結構

function quickSort_one(arr){
    if(arr.length < 1){
            return [];
    }
    var left = [],right = [],flag = arr[0];
    for(var i=1;i<arr.length;i++){
        if(arr[i] <= flag){
            left.push(arr[i]);
        }else{
            right.push(arr[i]);
        }
    }
    return quickSort_one(left).concat(flag,quickSort_one(right));
}

function quickSort_two(arr){
    function sort(start,end){
        if(start + 1 > end){
            return;
        }
        var flag = arr[start],f = start,l = end;
        while(f < l){
            while(f < l && arr[l] > flag){
                l--;
            }
            arr[f] = arr[l];
            while(f < l && arr[f] <= flag){
                f++;
            }
            arr[l] = arr[f];
        }
        arr[f] = flag;
        sort(start,f-1);
        sort(f+1,end);   
    }
    sort(0,arr.length-1);
}

function quickSort_three(arr){
    arr.sort(function(a,b){
        return a-b;
    });
}

function countTime(fn,arr){
    var start = Date.now();
    fn(arr);
    var end = Date.now();
    console.log(end - start);
}

function randomVal(num){
    var arr = [];
    for(var i=0;i<num;i++){
        arr.push(Math.ceil(Math.random()*num));
    }
    return arr;
}

在chrome下的一個運行狀況(以100000個數爲例,因爲每次排序後數組都發生了改變,因此每次都建立了新數組,以100000的基數來算的話,雖然不是同一個數組,可是結果也是值得參考的):dom

圖片描述

在firefox下的運行結果:數據結構和算法

圖片描述

不管是firefox仍是chrome,第一種排序算法的時間都是最長的,第二種是最快的,原生的sort方法比第二種方法稍微慢一點,但比第一種仍是快多了。性能

相關文章
相關標籤/搜索