Java数据结构与算法——分治法

一、分治的基本思想

将原问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后合并这些子问题的解来求原问题的解。

二、案例

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、分治与递归

分治法是一种算法,即分而治之;递归是一种实现,其特点是函数中调用自身。

递归是循环结构的一种,关键在于能够写出递归公式以及递归结束条件。分治法常常用到递归结构,但不是一定要使用递归!

发布了56 篇原创文章 · 获赞 0 · 访问量 942

猜你喜欢

转载自blog.csdn.net/weixin_45594025/article/details/104885793