目录
一、基本思想
分治,从字面上我们可以看出它的含义——分而治之,,它不是一个解决特定问题的算法,而是一种解决问题的思路。分治算法是有效算法设计中普遍采用的一种技术。
所谓“分而治之”就是把一个复杂的算法问题按照一定的“分解”方法分成等价的规模较小的若干部分,然后进行逐个解决,分别找出各部分的解,再把各部分的解组成整个问题的解。
也就是说,分治策略是如果一个规模为M的问题可以容易地解决则直接解决,否则将其分解成N个规模较小的子问题(N<=M),这些子问题相互独立且与原问题性质相同,那么我们只要求出子问题的解(递归解出这些子问题),然后将各个子问题的解合并就可以求出原问题的解。
二、基本步骤及适用情况
基本步骤:
适用情况:
- 原问题的规模缩小到一定程度就可以容易地解决;
- 若不能容易地解决原问题,判断该问题是否可以分解成若干个规模较小的相同问题;
- 利用该问题分解出的子问题的解可以合并得到原问题的解;(关键)
- 原问题分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。
三、常见算法使用
1、快速排序
快速排序,顾名思义,它是公认的最快的排序算法之一,有着广泛的应用。快速排序就是使用了分治算法的思想。
基本思路:
先在数组中确定一个“支点”(或称“基准”)(pivot),将所有小于这个“支点”的值都放在该点的左侧(右侧),大于这个“支点”的值都放在该点的右侧(左侧),与“支点”相同的数可以放在任一边,然后对左右两侧不断重复这个过程,直到所有排序完成。
支点左右侧的值根据排序规则来决定,如果从小到大排列,支点左侧就是比它小的值,右侧就是比它大的值。
时间复杂度:O(nlogn)
例:对数组[38,26,89,56,17,44]所有元素进行从小到大排序。
排序过程图如下:
代码实现:
/*以数组中间值为支点*/
function quickSort(arr,left,right){
var len = arr.length;
if(len<2) return arr;
left = (typeof left !== "number" ? 0:left);
right = (typeof right !== "number" ? len-1:right);
var index = Partition(arr,left,right);
if(left < index-1){
quickSort(arr,left,index-1);
}
if(index < right){
quickSort(arr,index,right);
}
return arr;
}
//分区操作
function Partition(arr,left,right){
var pivot = arr[Math.floor((left+right)/2)]; //以中间值为支点(基准点)
var i = left;
var j = right;
while(i<=j){
while(arr[i]<pivot){
i++;
}
while(arr[j]>pivot){
j--;
}
if(i<=j){
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
i++;
j--;
}
}
return i;
}
var arr = [38,26,89,56,17,44];
var left = 0;
var right = arr.length-1;
console.log("快速排序前的数组是:",arr);
arr = quickSort(arr,left,right);
console.log("快速排序后的数组是:",arr);
实现效果如下:
2、归并排序
归并排序,是建立在归并操作上的一种有效的排序算法,这是一种被广泛使用的排序方法。归并排序算法也是采用分治法的一个非常典型的应用。
基本思路:
归并排序的思想是:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再试子序列段间有序,最终合并成一个有序表。
采用归并方法对数组进行排序的基本方法是:将数组不断拆成两半,直到每一半只包含零个元素或一个元素为止,然后就用merge函数,将拆成两半的数组不断合并,直到合并成一整个排序完成的数组。
时间复杂度:O(nlogn)
例:对数组[38,26,89,56,17,44]所有元素进行从小到大排序。
排序过程图如下:
代码实现:
function mergeSort(arr,left,right,temp){
if(arr.length<2){
return arr;
}
var mid = Math.floor((left+right)/2);
if(left<right){
mergeSort(arr,left,mid,temp);
mergeSort(arr,mid+1,right,temp);
}
merge(arr,left,right,temp);
return arr;
}
//合并过程
function merge(arr,left,right,temp){
var i = left;
var mid = Math.floor((left+right)/2);
var j = mid+1;
var t = 0;
while(i<=mid && j<=right){
if(arr[i]<arr[j]){
temp[t] = arr[i];
i++;
t++;
}else{
temp[t] = arr[j];
j++;
t++;
}
}
while(i<=mid){
temp[t] = arr[i];
i++;
t++;
}
while(j<=right){
temp[t] = arr[j];
j++;
t++;
}
t = 0;
var k = left;
while(k<=right){
arr[k] = temp[t];
k++;
t++;
}
}
var arr = [38,26,89,56,17,44];
var temp = [];
var left = 0;
var right = arr.length-1;
console.log("归并排序前的数组是:",arr);
arr = mergeSort(arr,left,right,temp);
console.log("归并排序后的数组是:",arr);
实现效果如下: