用Java实现递归与分治系列(二)

分治法的基本思想

将一个规模为n的问题分解成k个规模较小的子问题,这些子问题互相独立且与原问题相同。递归地解决这些子问题,然后将各子问题的解合并得到原问题的解。

(一)二分搜索技术

二分搜索技术利用了元素间的次序关系,采用分治策略,其基本思想是:将n个元素分成个数大致相同的凉拌,取a[n/2]与x作比较。如果x=a[n/2],则找到x,如果x<a[n/2],则只在数组a的左半边查找,如果x>a[n/2],则只在右半边查找。

public class Binary_Search {

	public static void main(String[] args) {
		Binary_Search bi=new Binary_Search();
		
		int arr[]={1,2,3,4,5,6,7,8,9,10};
		bi.Search(arr, 0, arr.length-1, 5);
	}
	
	public int Search(int arr[],int left,int right,int s) {
	
		int middle=(left+right)/2;

		if(s==arr[middle]) {
			System.out.println(middle);//打印目标值所在数组的下标
			return middle;
		}
		
		if(s<arr[middle]) {
			Search(arr,left,middle-1,s);//递归调用,分治
		}
		
		if(s>arr[middle]) {
			Search(arr,middle+1,right,s);//递归调用,分治
		}
		
		return 1;
	}	
}

(二)棋盘覆盖问题

问题描述:在一个2k×2k个方格组成的棋盘中,若有一个方格与其他方格不同,则称该方格为特殊方格,且称该棋盘为特殊棋盘。我们要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
在这里插入图片描述
思路:用分治策略,可以设计解棋盘覆盖问题的一个简洁的算法。特殊方格必位于4个较小棋盘之一中,其余三个棋盘无特殊方格。为了将这三个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的汇合处。这三个子棋盘被L骨牌覆盖的方格就成为该棋盘上的特殊方格,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为1x1棋盘。
代码如下

public class ChessBoard{
	int tile=1;
	static int board[][]=new int[8][8];
	public static void main(String[] args) {
		ChessBoard cb=new ChessBoard();
		cb.chessboard(0,0,1,1,8);
		for(int i=0;i<board.length;i++) {
			for(int j=0;j<board.length;j++) {
				System.out.print(String.format("%3d", board[i][j]));
			}
			System.out.println();
		}
	}
	
	/*
	 * tr:棋盘的行
	 * rc:棋盘的列
	 * dr:特殊棋格的行
	 * dt:特殊棋格的列
	 * s:棋盘大小
	 */
	public void chessboard(int tr,int tc,int dr,int dc,int size) {
		if(size==1) {
			return;
		}
		int t=tile++;
		int s=size/2;
		//覆盖左上角的棋盘
		if(dr < tr+s && dc < tc+s) {
			chessboard(tr,tc,dr,dc,s);//特殊方格在该棋盘
		}else {
			board[tr+s-1][tc+s-1]=t;//特殊方格不在该棋盘
			chessboard(tr,tc,tr+s-1,tc+s-1,s);
		}
		
		//覆盖右上角的棋盘
		if(dr < tr+s && dc >= tc+s) {
			chessboard(tr,tc+s,dr,dc,s);//特殊方格在该棋盘
		}else {
			board[tr+s-1][tc+s]=t;//特殊方格不在该棋盘
			chessboard(tr,tc+s,tr+s-1,tc+s,s);
		}
			
		//覆盖左下角的棋盘
		if(dr >= tr+s && dc < tc+s) {
			chessboard(tr+s,tc,dr,dc,s);//特殊方格在该棋盘
		}else {
			board[tr+s][tc+s-1]=t;
			chessboard(tr+s,tc,tr+s,tr+s-1,s);
		}
			
		//覆盖右下角的棋盘
		if(dr>=tr+s && dc>=tc+s) {
			chessboard(tr+s,tc+s,dr,dc,s);
		}else {
			board[tr+s][tc+s]=t;
			chessboard(tr+s,tc+s,tr+s,tc+s,s);
		}
		
	}

}	

程序运行结果如下
在这里插入图片描述

(三)合并排序

合并排序算法是用分治策略实现对n个元素进行排序的算法,其基本思想是:将待排序元素分成大小大致相同的两个子集合,然后分别对两个子集合进行排序,最后将两个排好序的子集合并成按要求排序的集合。

public class MergeSort {

	static int arr[]= {23,45,76,3,8,5,46,4};//待排序数组
	static int temp[]=new int[arr.length];//过渡数组
	
	public static void main(String[] args) {
		MergeSort ms=new MergeSort();
		ms.mergesort(arr,temp,0,arr.length-1);
		//打印输出排完序后的情况
		for(int i=0;i<arr.length;i++) {
			System.out.print(arr[i]+" ");
		}
	}
	
	public void mergesort(int arr[],int temp[],int left,int right) {
		
		if(left<right) {
			int middle=(left+right)/2;
			mergesort(arr,temp,left,middle);
			mergesort(arr,temp,middle+1,right);
			merge(arr,temp,left,middle,right);
		}
		
	}
	public void merge(int arr[],int temp[],int left,int middle,int right) {
		int i=0;
		int j=left,k=middle+1;
		//遍历寻找
		while(j<=middle&&k<=right) {
			if(arr[j]<arr[k]) {
				temp[i++]=arr[j++];
			}else {
				temp[i++]=arr[k++];
			}
		}
		//当有一个数组为空时直接存到数组里面
		while(j<=middle) {
			temp[i++]=arr[j++];
		}
		while(k<=right) {
			temp[i++]=arr[k++];
		}
		//把临时数组中的元素复制到目标数组中
		for(int m=0;m<i;m++) {
			arr[left+m]=temp[m];
		}
	}
}

(四)快速排序

快速排序算法也是基于分治策略的一个算法,其基本思想是:在数组中选一个基准数(通常为数组第一个),将数组中小于基准数的数据移到基准数左边,大于基准数的移到右边, 对于基准数左、右两边的数组,不断重复以上两个过程,直到每个子集只有一个元素,即为全部有序。即:
1,分解
2,递归求解
3,合并

public class QuickSort {
	static int array[]={12,43,6,2,56,5};
	public static void main (String[] args){
			QuickSort qs=new QuickSort();
			qs.quickSort(arr,0,arr.length-1);
			for(int i=0;i<arr.length;i++){
			System.out.print(array[i]+" ");
		}
	}
    private static void quickSort(int[] array, int left, int right) {
        if (left>=right) {
            return;
        }
        int i = left, j = right,int index = array[i]; //选择第一个数为基准数
        while (i < j) {
            while (i < j && array[j] >= index) { 
                j--;
            }
            if (i < j) {
                array[i++] = array[j]; 
            }
            while (i < j && array[i] < index) {
                i++;
            }
            if (i < j) {
                array[j--] = array[i]; 
            }
        }
        array[i] = index; // 将基准数填入
        quickSort(array, left, i - 1); // 递归调用,分治
        quickSort(array, i + 1, right); // 递归调用,分治
    }


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分治归算法是计算机科学中的两种重要算法思想,它们可以帮助我们解决很多复杂的问题。下面我介绍一下这两种算法以及它们在Java中的实现。 1. 分治算法 分治算法是指将一个大问题分成若干个小问题,然后逐个解决这些小问题,最后将所有小问题的解合并起来得到大问题的解。分治算法通常采用归的方式来实现Java代码示例: ```java public int divideAndConquer(int[] nums, int left, int right){ if(left == right) return nums[left]; // 如果数组只有一个元素,则直接返回该元素 int mid = (left + right) / 2; // 将数组分成两部分 int leftSum = divideAndConquer(nums, left, mid); // 归求解左半部分的和 int rightSum = divideAndConquer(nums, mid + 1, right); // 归求解右半部分的和 return leftSum + rightSum; // 合并左右两部分的和 } ``` 上面的代码实现了求解一个数组中所有元素的和的问题。首先将数组分成两部分,然后归地求解左右两部分的和,最后将左右两部分的和合并起来得到整个数组的和。 2. 归算法 归算法是指在函数的定义中调用自身的算法。归算法通常用于解决具有归结构的问题,比如树和图等数据结构。归算法需要满足两个条件:基本情况和归情况。 Java代码示例: ```java public int fibonacci(int n){ if(n <= 1) return n; // 基本情况 return fibonacci(n-1) + fibonacci(n-2); // 归情况 } ``` 上面的代码实现了求解斐波那契数列的第n项的值的问题。斐波那契数列中的第一项和第二项都是1,从第三项开始,每一项都是前两项的和。归算法中,基本情况是当n小于等于1时直接返回n,归情况是求解前两项的和,然后归求解前两项中的每一项。 希望这些示例代码能够帮助你理解分治归算法的基本思想和Java实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值