《软件技术基础》之《分治与递归》

引例——最短路径选择

在这里插入图片描述
将这个问题分成3个小问题:求A到B的最短路径、求B到C的最短路径、求C到D的最短路径。最后将这3个小问题的解合并起来,即是原问题的解。

分治是解编程题常用的一种思想,而大多数分治思想都是用递归来实现的。下面来分别介绍这两个概念,并给出它们的应用场景。

分治

分治(divide and conquer)的全称称为“分而治之”,分治即是将大问题划分为若干个规模较小、可以直接解决的子问题,然后解决这些子问题,最后将这些子问题的解合并起来,即是原问题的解。

分治是一种思想,它不涉及到具体的算法,而大多数情况下,分治都是借由递归来实现的。

凡治众如治寡,分数是也。——孙子兵法

在这里插入图片描述
分治法的适用条件:

  • 该问题的规模缩小到一定程度就可以容易地解决;
  • 该问题可以分解为若干个规模较小的相同问题,即题具有最优子结构性质
  • 利用该问题分解出的子问题的解可以合并为该问题的解;
  • 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

这条特征涉及到分治法的效率,如果各子问题是不独立的,则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然也可用分治法,但一般用动态规划较好。

递归

递归是一个很难阐述的概念。从c语言角度来讲,递归就是这个函数反复调用自身,然后将问题一步步地缩小,直到这个问题已经缩小到可以直接解决的程度,然后再一步一步地返回,最终解决原问题。

递归的逻辑中有两个重要的概念:

  1. 递归边界。递归边界是分解的尽头。
  2. 递归式。递归式是将问题规模一步步缩小的手段。

n的阶乘和Fibonacci数列的求解过程都很好地体现了这种思想。

n的阶乘

我们知道,且0 != 1,我们可以把0!当作递归边界,N!的递归式可以用N*(N-1)!来表示。

代码:

int  factorial(n)
{
    if(0 == n) return 1;
    else return n*factorial(n-1);
}

Fibonacci数列

如果说兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。假设所有兔子都不会死去,能够一直干下去,那么一年以后可以繁殖多少对兔子呢?
在这里插入图片描述
用数学函数来定义:
在这里插入图片描述
代码:

int Fibonacci(int n)
{
     if(n==0||n==1)return 1;
     else return Fibonacci(n-1)+Fibonacci(n-2);
}

合并(归并)排序

合并排序是采用分治法,先将无序序列划分为有序子序列,再将有序子序列合并成一个有序序列的有效的排序算法。
在这里插入图片描述

基本原理:先将无序序列利用二分法划分为子序列,直至每个子序列只有一个元素(单元素序列必有序),然后再对有序子序列逐步(两两)进行合并排序。合并方法是循环的将两个有序子序列当前的首元素进行比较,较小的元素取出,置入合并序列的左边空置位,直至其中一个子序列的最后一个元素置入合并序列中。最后将另一个子序列的剩余元素按顺序逐个置入合并序列尾部即可完成排序。

示例:
在这里插入图片描述
代码实现:

public static void mergeSort(Comparable a[],int left,int right)
{
	if(left<right)
	{// 至少有2个元素
		int i=(left+right)/2; // 取中点
		mergeSort(a,left,i);
		mergeSort(a,i+1,right);
		merge(a,b,left,i,right); // 合并到数组b
		copy(a,b,left,right);//复制回数组a
	}
	sort(a);
}

合并排序完整代码参考:
合并(归并)排序原理及代码实现(c/c++)
【排序算法】归并排序(C++实现)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值