基本算法-分治算法

分治算法的基本思想

当我们遇到要处理的数据相当多,或求解过程相当复杂的问题的时候。我们可以把它分解成若干的个子问题,若子问题还是很复杂,我们可以继续分解,直到解出问题为止。

首先我们看去数组的最值的问题。取最值可以直接用比较法依次比较,但是如果遇到数据量比较大的情况比较下来速度会比较慢。我们可以 将数组分成两堆,分别取他们的最值,他们取到的最值进行比较,得到结果。

public static int getMaxValue(int[] array){
	int length = array.length;
	//数组只有一个值直接返回
	if(length==1){
		return array[0];
	}
	//数组只有两个值比较取最大值返回
	if(length==2){
		return array[0]>array[1]?array[0]:array[1];
	}
	//数组只有超过两个值拆分成两个数组array1和array2
	int length1 = array.length/2;
	int[] array1 = new int[length1];
	for (int i = 0; i < length1; i++) {
		array1[i] = array[i];
	}
	int length2 = length-length1;
	int[] array2 = new int[length2];
	for (int i = length1; i < length; i++) {
		array2[i-length1] = array[i];
	}
	//分别取两组数据的最值
	int i = getMaxValue(array1);
	int j = getMaxValue(array2);
	//比较返回
	return i>j?i:j;
}

测试结果:

使用场景

使用分治法能解决的问题一般具有几个特征:

  1) 规模缩小到一定的程度就可以容易地解决;

  2) 可以分解为规模较小的相同问题;

  3) 分解而成的小问题在结果可以合并;

  4) 该问题所分解出的各个子问题是相互独立的,不包含公共的子问题。

解决步骤

        1)分解,将要解决的问题划分成若干规模较小的同类问题;

        2)求解,当子问题划分得足够小时,用较简单的方法解决;

        3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。

经典问题

 1、二分查找

  二分查找是一种效率较高得查找方法,二分查找必须是有序表。二分查找的查询过程:首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

  二分查找步骤:1、先确定中间位置;2、将待查找得值key与中间值比较。若相等,则查找成功并返回该位置,否则须确定新得查找区间,继续二分查找,具体如下:如果中间值大于key,由于数据为有序线性表,则结果一定在左边,否则在右边。然后继续上述步骤,直到中间值和key相等为止。

/**
  * 返回数组data中key值得索引
  * @param data查找对象
  * @param left查找范围左
  * @param right查找范围右
  * @param key待查找内容
  * @return
  */
public static int search(int[] data,int left,int right,int key){
	//获取中间位置
	int middle = (left+right)/2;
	//若key值如相等返回当前位置,否则继续查找
	if(data[middle] == key){
		return middle;
	}else if(data[middle] >key){
		return search(data, left, middle-1, key);
	}else{
		return search(data, middle+1, right, key);
	}
}

测试结果:

2、全排列问题

       输出一个数组的的全排列。如果数组大小为1是全排列就是它自己;如果数组大小为n大于1时,可以把数组分成第一个数据和其他数据的组成的数组,这个数据作为全排列的第一个,第一数据有n种可能,分成n个分支,剩下的n-1在进行全排列,重复上述操作,得到的数据作为全排列的第二个,依次类推。

/**
* 创建一个全局变量用于接收全排列的结果
*/
public static List<Integer> list = new ArrayList<>();
public static void FullPermutation(int[] arr){
	//结束条件
	if(arr.length<2 && arr.length>0){
		list.add(arr[0]);
		System.err.println(list);	
		list.remove(list.size()-1);
	}
	for (int i =0;i<arr.length;i++){
		list.add(arr[i]);
		//将本次循环数据的以外的添加到新的数组中
		int[] arr1 = new int[arr.length-1];
		int k = 0;
		for(int j =0;j<arr.length;j++){
			if(i==j){
				continue;
			}
			arr1[k] = arr[j];
			k++;
		}
		//递归调用
		FullPermutation(arr1);
		//每次循环结束将这次循环添加的数据剔除
		list.remove(list.size()-1);
	}
}

      

总结

运用分治策略解决的问题一般来说具有以下特点:

1、原问题可以分解为多个子问题,这些子问题与原问题相比,只是问题的规模有所降低,其结构和求解方法与原问题相同或相似;

2、原问题在分解过程中,递归地求解子问题,由于递归都必须有一个终止条件,因此,当分解后的子问题规模足够小时,应能够直接求解;

3、在求解并得到各个子问题的解后,应能够采用某种方式、方法合并或构造出原问题的解。

在分治策略中,由于子问题与原问题在结构和解法上的相似性,用分治方法解决的问题,大都采用了递归的形式。在各种排序方法中,如归排序、堆排序、快速排序等,都存在有分治的思想。

猜你喜欢

转载自blog.csdn.net/qq_36154832/article/details/88422330
今日推荐