一、分治的基本思想
将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后合并这些子问题的解来求原问题的解。
二、案例
1、求数组的最大最小值
算法思想:
- 若数组中只有一个元素,则该元素既是最大值,也是最小值;
- 若数组中只有两个元素,则较大的为最大值,较小的为最小值;
- 若数组中包含的元素个数大于 2,则按下标将数组从中间分为两个子数组,比较左子数组的最小值与右子数组的最小值,较小的为最小值,比较左子数组的最大值与右子数组的最大值,较大的为最大值。递归进行这一步,直至子数组中元素个数小于或等于 2。
代码如下:
class MinMax{
private int min;
private int max;
public MinMax(int min, int max) {
this.min = min;
this.max = max;
}
public int getMin() {
return min;
}
public void setMin(int min) {
this.min = min;
}
public int getMax() {
return max;
}
public void setMax(int max) {
this.max = max;
}
}
public class FindMinMax {
public static MinMax findMinMax(int[] array, int start, int end){
if(end - start <= 1){// 数组元素个数小于等于2
if(array[start] > array[end]){
return new MinMax(array[end], array[start]);
}else{
return new MinMax(array[start], array[end]);
}
}else{// 数组元素个数大于2
int middle = (start + end) >>> 1;
MinMax left = findMinMax(array, start, middle);
MinMax right = findMinMax(array, middle + 1, end);
int min = 0;
int max = 0;
min = left.getMin() > right.getMin() ? right.getMin() : left.getMin();
max = left.getMax() > right.getMax() ? left.getMax() : right.getMax();
return new MinMax(min, max);
}
}
public static void main(String[] args) {
int[] array = {1, 4, 6, 5, 3, 10, 8};
MinMax m = findMinMax(array, 0, array.length - 1);
System.out.println("min = " + m.getMin());
System.out.println("max = " + m.getMax());
}
}
测试结果:
min = 1
max = 10
2、分治法实现归并排序
归并排序,就是利用归并思想实现的排序方法。它的原理是:假设初始序列含有 n 个记录,则可以看成 n 个有序的子序列,每个子序列的长度为 1,然后两两归并,得到(n/2)个长度为 2 或 1的有序子序列;再两两归并,…,如此重复,直至得到一个长度为 n 的有序序列为止。
代码如下:
public class MergeSort {
public static void merge(int[] array, int start, int middle, int end){
int[] temp = new int[end - start + 1];
int i = start;// 左边数组的起始位置
int j = middle + 1;// 右边数组的起始位置
int k = 0;
// 左边数组和右边数组都有元素
while(i <= middle && j <= end){
if(array[i] <= array[j]){
temp[k++] = array[i++];
}else{
temp[k++] = array[j++];
}
}
// 左边数组有元素(右边数组没有元素了)
while(i <= middle){
temp[k++] = array[i++];
}
// 右边数组有元素(左边数组没有元素了)
while(j <= end){
temp[k++] = array[j++];
}
for (int a = 0; a < temp.length; a++) {
array[a + start] = temp[a];
}
}
public static void mergeSort(int[] array, int start, int end){
int middle = (start + end) / 2;
if(start < end){
mergeSort(array, start, middle);// 递归排序左半部分
mergeSort(array, middle + 1, end);// 递归排序右半部分
merge(array, start, middle, end);// 归并
}
}
public static void main(String[] args) {
int[] array = {1, 4, 3, 8, 9, 5};
System.out.print("排序前:");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
mergeSort(array, 0, array.length - 1);
System.out.print("排序后:");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
}
测试结果:
排序前:1 4 3 8 9 5
排序后:1 3 4 5 8 9
参考之前的归并排序:https://blog.csdn.net/weixin_45594025/article/details/104258094
三、小结
1、数学归纳法使用的是分治思想
只要问题可以用数学归纳法来表示,首先就应该想到分治法。数学归纳用同一个函数来表述不同规模的问题,套用递归结构,可迅速解决问题。
2、分治法的核心在于“分”
怎么把一个大问题分解为若干小问题。
3、分治与递归
分治法是一种算法,即分而治之;递归是一种实现,其特点是函数中调用自身。
递归是循环结构的一种,关键在于能够写出递归公式以及递归结束条件。分治法常常用到递归结构,但不是一定要使用递归!