归并排序和快速排序总结
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);