递归小结 来证明 摆速班确读售混亡显容景理数霸漆 优点:练 带来很大方便。 的运行效率较低,无论是耗费的计算 储空间都比非递归算法要多
12 递归小结 优点:结构清晰,可读性强,而且容易用数学归纳法 来证明算法的正确性,因此它为设计算法、调试程序 带来很大方便。 缺点:递归算法的运行效率较低,无论是耗费的计算 时间还是占用的存储空间都比非递归算法要多
递归小结 解决方法:在递归算法中消除递归调用,使其转化为非递归算法。 1、采用一个用户定义的栈来模拟系统的递归调用工作栈。该方法 通用性强,但本质上还是递归,只不过人工做了本来由编译器做的 事情,优化效果不明显。 2、用递推来实现递归函数 3、通过变换能将一些递归转化为尾递归,从而迭代求出结果 后两种方法在时空复杂度上均有较大改善,但其适用范围有限
13 递归小结 解决方法:在递归算法中消除递归调用,使其转化为非递归算法。 1、采用一个用户定义的栈来模拟系统的递归调用工作栈。该方法 通用性强,但本质上还是递归,只不过人工做了本来由编译器做的 事情,优化效果不明显。 2、用递推来实现递归函数。 3、通过变换能将一些递归转化为尾递归,从而迭代求出结果。 后两种方法在时空复杂度上均有较大改善,但其适用范围有限
分治法 Divide:将问题划分为若干子问题 Conquer:递归地解决每一个子问题 ● Combine:合并子问题的解 ●例归并排序
14 ⚫ Divide: 将问题划分为若干子问题 ⚫ Conquer: 递归地解决每一个子问题 ⚫ Combine: 合并子问题的解 ⚫ 例 归并排序 分治法
分治法的适用条件 分治法所能解决的问题一般具有以下几个特征 ●该问题的规模缩小到一定的程度就可以容易地解决 该问题可以分解为若干个规模较小的相同问题,即该问题具有 最优子结构性质 利用该问题分解出的子问题的解可以合并为该问题的解; 该问题所分解出的各个子问题是相互独立的,即子问题之间不 包含公共的子问题 这条特征涉及到分治法的效率,如果各子问题是不独立的 则分治法要做许多不必要的工作,重复地解公共的子问题, 此时虽然也可用分治法,但一般用动态规划较好。 15
15 分治法的适用条件 分治法所能解决的问题一般具有以下几个特征: ⚫ 该问题的规模缩小到一定的程度就可以容易地解决; ⚫ 该问题可以分解为若干个规模较小的相同问题,即该问题具有 最优子结构性质 ⚫ 利用该问题分解出的子问题的解可以合并为该问题的解; ⚫ 该问题所分解出的各个子问题是相互独立的,即子问题之间不 包含公共的子问题。 因为问题的计算复杂性一般是随着问题规模的增加而增加, 因此大部分问题满足这个特征。 这条特征是应用分治法的前提,它也是大多数问题可以满足 的,此特征反映了递归思想的应用 能否利用分治法完全取决于问题是否具有这条特征,如果具 备了前两条特征,而不具备第三条特征,则可以考虑贪心算 法或动态规划。 这条特征涉及到分治法的效率,如果各子问题是不独立的, 则分治法要做许多不必要的工作,重复地解公共的子问题, 此时虽然也可用分治法,但一般用动态规划较好
分治法的基本步骤: divide-and-conquer(P) if(|P|<=no) adhoc(P),∥/解决小规模的问题 divide p into smaller subinstances p,P2,,Pk;/分解问题 for(=1,i<=k,i++) yi= divide-and- conquer(Pi),/递归的解各子问题 return merge(yl,,yk)/将各子问题的解合并为原问题的解
16 分治法的基本步骤: divide-and-conquer(P) { if ( | P | <= n0) adhoc(P); //解决小规模的问题 divide P into smaller subinstances P1,P2,...,Pk;//分解问题 for (i=1,i<=k,i++) yi=divide-and-conquer(Pi); //递归的解各子问题 return merge(y1,...,yk); //将各子问题的解合并为原问题的解 } 人们从大量实践中发现,在用分治法设计算法时,最好使子 问题的规模大致相同。即将一个问题分成大小相等的k个子 问题的处理方法是行之有效的。这种使子问题规模大致相等 的做法是出自一种平衡(balancing)子问题的思想,它几乎 总是比子问题规模不等的做法要好