归并排序和快速排序总结

本文总结了归并排序和快速排序两种经典算法,介绍了它们的基本思路——分治法。归并排序侧重于如何有效地‘归并’,而快速排序则在‘分’的策略上下功夫。同时,文章探讨了由这两种排序算法衍生的问题,如如何利用归并排序在O(nlogn)时间复杂度内求解数组中的逆序对数量,以及如何通过快速排序在O(n)复杂度内找到数组中的第N大元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序和快速排序总结

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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值