天天看點

歸并排序和快速排序總結歸并排序和快速排序總結

歸并排序和快速排序總結

1. 算法基本思路:分治

分治,字面上的解釋是“分而治之”,就是把一個複雜的問題分成多個同等結構的子問題,再把子問題分成更小的子問題……直到最後子問題可以簡單的直接求解,原問題的解即子問題的解的合并。歸并排序和快速排序都采用了二分法思想。不同之處在于,歸并排序在“分”的問題上是簡單的一刀切,而将重點放在了如何“歸并”上。而快速排序則花了很大的功夫在如何“分”這個問題上,“歸并”則變得非常簡單。

2. 由歸并排序和快速排序衍生出來的問題

2.1 求數組中的逆序對

“逆序對”,顧名思義,即從數組中随意抽出兩個數,如果前一個數比後一個數大,則稱這兩個數為逆序對。數組中逆序對的數量可以衡量數組的有序程度。如果數組為完全升序的數組,那麼任意抽出一個數對都會是順序對;而如果數組為完全倒序的數組,則任意抽出一個數對都為逆序對。那麼,該如何利用歸并排序的思想更加快速的求解數組中的逆序對數量呢?

比如說對數組2,3,6,8和數組1,4,5,7進行歸并的時候,發現1比2小,則可以斷定,1比2之後的所有元素都要小,則此處一共有4個逆序數組。按照這種思路,能以nlogn的效率計算一個數組中的逆序對。

/**
 * 利用歸并排序的思路,計算數組中逆序對的個數
 * @param  {Array} arr   待計算的數組
 * @param  {Number} left  左邊界
 * @param  {Number} right 右邊界
 * @return {Number}       傳回逆序對的個數
 */
function countReverseOrder(arr,left,right){
    if (left >= right) {
        return ;
    }
    var mid = Math.floor((left + right)/);
    var countL = countReverseOrder(arr,left,mid,count);
    var countR = countReverseOrder(arr,mid+,right,count);

    //歸并
    var leftPart = arr.slice(left,mid+);
    var rightPart = arr.slice(mid+,right+);
    var l = ;
    var r = ;
    var count = countL + countR;
    for (var i = left; i <= right; i++) {
        if (l >= leftPart.length) {
            arr[i] = rightPart[r];
            r ++;
        } else if (r >= rightPart.length) {
            arr[i] = leftPart[l];
        } else if (leftPart[l] > rightPart[r]) {
            arr[i] = rightPart[r];
            r ++;
            count += leftPart.length - l;
        } else {
            arr[i] = leftPart[l];
            l ++;
        }
    }
    return count;
}

var arr = [,,,,,,,];
countReverseOrder(arr,,arr.length-,);//11
           

2.1 求數組中第N大的元素(O(n)複雜度)

利用快速排序的思路,可以很友善的求出數組中第N大的元素,其時間複雜度為O(n)。實質上,算法複雜度= n + n/2 + n/4 + n/8 +……+ 1 = O(2n)。

Array.prototype.changeData = function(indexOne,indexTwo){
    var temp = this[indexOne];
    this[indexOne] = this[indexTwo];
    this[indexTwo] = temp;
};

function findTopN(arr,lIndex,rIndex,n){
    arr.changeData(lIndex,Math.floor(Math.random()*(rIndex-lIndex+)+lIndex));
    var i = lIndex;
    // var j = lIndex + 1;
    var v = arr[lIndex];
    for (var j = lIndex + ; j <= rIndex; j++) {
        if (arr[j] < v) {
            arr.changeData(j,i+);
            i ++;
        }
    }
    arr.changeData(i,lIndex);
    if (i == n-) {
        return arr[i];
    } else if(i > n-){
        return findTopN(arr,lIndex,i-,n);
    } else {
        return findTopN(arr,i+,rIndex,n);
    }
}

var arr = [,,,,,,,];
findTopN(arr,,arr.length-,);
           

繼續閱讀