归并排序和快速排序总结

归并排序和快速排序总结

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 0;
    }
    var mid = Math.floor((left + right)/2);
    var countL = countReverseOrder(arr,left,mid,count);
    var countR = countReverseOrder(arr,mid+1,right,count);

    //归并
    var leftPart = arr.slice(left,mid+1);
    var rightPart = arr.slice(mid+1,right+1);
    var l = 0;
    var r = 0;
    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 = [3,2,6,8,4,1,5,7];
countReverseOrder(arr,0,arr.length-1,0);//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+1)+lIndex));
    var i = lIndex;
    // var j = lIndex + 1;
    var v = arr[lIndex];
    for (var j = lIndex + 1; j <= rIndex; j++) {
        if (arr[j] < v) {
            arr.changeData(j,i+1);
            i ++;
        }
    }
    arr.changeData(i,lIndex);
    if (i == n-1) {
        return arr[i];
    } else if(i > n-1){
        return findTopN(arr,lIndex,i-1,n);
    } else {
        return findTopN(arr,i+1,rIndex,n);
    }
}

var arr = [3,2,6,8,4,1,5,7];
findTopN(arr,0,arr.length-1,3);

你可能感兴趣的:(算法与数据结构)