递归与分治

递归与分治递归算法是指直接或者间接调用自身的算法,分治算法是指将一个问题规模分为n个规模小、方便处理的子问题,最后再将这些子问题得到的结果合并。在计算机求解问题的过程中,计算时间与问题的规模呈正比,问题规模越大越难处理,规模越小就容易处理。因此当遇到问题无法处理时,可以考虑能不能将之转化为规模较小的问题,递归和分治经常一起使用。汉诺塔问题设a、b和c是3个塔座:开始时,塔座a上有n个自上而下...
摘要由CSDN通过智能技术生成

递归与分治

递归算法是指直接或者间接调用自身的算法,分治算法是指将一个问题规模分为n个规模小、方便处理的子问题,最后再将这些子问题得到的结果合并。在计算机求解问题的过程中,计算时间与问题的规模呈正比,问题规模越大越难处理,规模越小就容易处理。因此当遇到问题无法处理时,可以考虑能不能将之转化为规模较小的问题,递归和分治经常一起使用。

汉诺塔问题

设a、b和c是3个塔座:开始时,塔座a上有n个自上而下、由小到大地叠在一起圆盘,各圆盘从小到大编号为1, 2, …, n,现要求将塔座a上的这一叠圆盘移到塔座b上,并仍按同样顺序叠置,移动圆盘时遵守以下移动规则:
规则1:每次只能移动1个圆盘;
规则2:不允许将较大的圆盘压在较小的圆盘之上;
规则3:在满足移动规则1和2的前提下,可将圆盘移至a、b和c中任一塔座上。
(1) 算法设计思路
①要是n为1的话,直接将圆盘从a移动到b即可
②要是n大于1的话,要将n个圆盘从a移动到b,可以先将上面的n-1个圆盘从a移动到c再将最底下的圆盘移动到b,这样就移动了当前最大的圆盘到了相应位置,接下来就考虑将剩下的n-1个圆盘从c移动到b,此时只要借助a,将c上的n-2歌圆盘移动到a,那么此时就能将第n-1个圆盘从c移动到b,这样一来,每次问题的规模越来越小,直到变成①中的情况。

(2) 算法实现的伪码
函数:move(a, b, c, n)
输入:前三个参数为三座塔,n为个数,即将n个圆盘从a借助c移动到b
输出:输出语句“将圆盘x从x移动到x”
S1: if n==1
S2: then print “将圆盘”+n+“从”+a+“移动到”+b
S3: else move(a, c, b, n-1)//将n-1个圆盘从a借助b移动到c
S4: print “将圆盘”+n+“从”+a+“移动到”+b
S5: move(c, b, a, n-1)//将n-1个圆盘从c借助a移动到b

(3) 算法实现的源码

private static void move(char a, char b, char c, int n) {
	if(n == 1) {
		System.out.println("将圆盘"+n+"从"+a+"移动到"+ b);
	}else {
		move(a, c, b, n-1);//调用子问题
		System.out.println("将圆盘"+n+"从"+a+"移动到"+b);
		move(c, b, a, n-1);
	}	
}

(4) 算法运行结果
move(‘a’, ‘b’, ‘c’, 1)结果为:
在这里插入图片描述
move(‘a’, ‘b’, ‘c’, 3)结果为:
在这里插入图片描述

(5) 算法的时间复杂性分析
在该算法中,如果n为1,时间复杂度为O(1)
若n大于1,则开销为将n-1个圆盘从a移动到c,将1个圆盘从a移动到b,将n-1个圆盘从c移动到b,总计为T(n-1)+O(1)+T(n-1)
所以T(n)=2*T(n-1)+T(1)
所以时间复杂度为O(2^n)

归并排序是经典的分治算法
以{28, 4, 94, 32, 15, 76, 23, 56, 85, 12}的排序为例:

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int[] workSpace = {28, 4, 94, 32, 15, 76, 23, 56, 85, 12};
		mergeSort(workSpace, 0, workSpace.length-1);
		for (int i = 0; i < workSpace.length; i++) {
			System.out.print(workSpace[i]+" ");
		}
	}
	public static void mergeSort(int[] workSpace, int first,int last) {
		if(first == last) {
			//first到last只有一个元素,不用排序
			return;
		}
		int[] newWorkSpace = new int[last - first +1];//存放该范围排序好的数组
		int mid = (last + first)/2;//找到中点
		//得到左右子问题排好序的结果
		mergeSort(workSpace, first, mid);
		mergeSort(workSpace, mid+1, last);
		int l = first, r = mid+1, n = 0;
		while(l <= mid && r <= last) {
			//每次都找到最小数放在新数组里面,并且更新选取的最小数的那个数组的下标
			newWorkSpace[n++] = workSpace[l] < workSpace[r] ? workSpace[l++] : workSpace[r++];
		}
		//以下两个数组是为了完整遍历完两个数组
		while(l <= mid) {
			newWorkSpace[n++] = workSpace[l++];
		}
		while(r <= last) {
			newWorkSpace[n++] = workSpace[r++];
		}
		//将排好序的数组赋值到原来位置
		for (int i = last; i >= first; i--) {
			workSpace[i] = newWorkSpace[--n];
		}
	}	
}

归并排序详见百科:

https://baike.baidu.com/item/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F/1639015?fr=aladdin

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值