递归与分治策略
递归与分治策略是算法中一类常见的策略或者说思想,很多问题都可以通过递归或者分治的策略进行处理。
递归
很难说递归算法起源于哪里(因为就计算机科学来说,使用循环是更为自然的算法),我相信递归思想的出现早于计算机出现很多年,其基本思路是确定一种算法,该算法对于 少数特定规模的输入即递归基, 仅进行常数时间的运算,在其他的输入规模下,该算法可以调用一个输入规模更小的自己,重复该过程直到调用递归基。
递归与递推公式
我已不了解数列是否还是高中数学的重点内容(也许它跑到初中去了呢),但是我仍然记得数列的递推公式的概念:数列的第n项依赖于数列的n项之前的某一项或者某几项,实际上这就是非常自然的递归算法,从他们的名字上应该也能看出相关性。
其中最经典的莫过于斐波那契数列了,该数列在数学和计算机科学乃至算法研究中都是掌上明珠。相当多的教材会使用斐波那契数列讲解递归算法。
分治策略
刚刚我们说到,递归算法的核心思想在于使用同样的算法(函数),其在大规模输入下的解依赖于更小的规模输入下的解的方式来降低输入的规模并以此求得所有规模输入下的问题的解,但是大体来说,减少问题的规模有两种常见的减少方式:1) 线性的降低问题的规模 . 2) 成比例的降低问题的规模. 所谓线性降低问题规模就是An 依赖于An-c其中c是一个常数,而比例规模大概就是An 依赖于An/c 其中c是一个常数。
对于线性降低问题规模的递归来说,常常容易找到一个与之等价的循环算法,因为循环算法免去了函数调用的开销,(以及其他的一些原因)线性降低问题规模的递归算法较少登场在初等的算法研究中。
而成比例降低输入规模的时候,我们可以看到递归树的深度与问题规模呈现对数关系,在算法中对数几乎总是好的因为它增长的非常慢,而且分治(将问题一分为n,就是把问题规模降低了n倍)策略是一种设计思路而非仅仅能用于少数的情况,故被研究的较多。
需要指出的是,大部分分治策略在降低问题规模后还需要将小规模输入下的算法的得到的结果合并起来,分治策略考虑相应算法需要的合并的部分,(如果不考虑合并部分的话,那所有分治算法的时间复杂度就是 l g n lgn lgn了,二分查找是不考虑合并的典型例子)。
归并排序
作为分治策略的经典案例,考察归并排序的算法,其基本思路为将要排序的数列等分为两份,分别归并排序二者,然后合并已经排好序的2个子数列。容易知道合并两个子数列的算法时间复杂度是子数列长度之和的线性时间。所以该算法的时间复杂度递归公式可以描述为
T
(
n
)
=
2
T
(
n
/
2
)
+
θ
(
n
)
T(n) = 2T(n/2) + \theta(n)
T(n)=2T(n/2)+θ(n)
其中
T
(
n
/
c
)
T(n/c)
T(n/c)来自于分治,将问题规模分成
c
c
c 等分,
θ
(
n
)
\theta(n)
θ(n)来自合并子结果,上式也体现了大多数分治策略算法的递推公式。
递归分析
对于如上的分治策略算法,研究渐进时间复杂度的最基本方法是递归树分析,即画出算法的递归树,找到算法的递归树深度,叶子节点数,每一层的树枝个数,并对归并时间求总和。
主方法
对于形如
T
(
n
)
=
a
T
(
n
/
b
)
+
f
(
n
)
T(n) = aT(n/b) + f(n)
T(n)=aT(n/b)+f(n)
其中
f
(
n
)
f(n)
f(n) 是渐进非负的。
这样的递推公式,可以使用主方法进行判断:
- 当 f ( n ) = O ( n l o g b a − ϵ ) f(n) = O(n^{log_ba - \epsilon}) f(n)=O(nlogba−ϵ) 的时候, T ( n ) = Θ ( n l o g b a ) T(n) = \Theta(n^{log_ba}) T(n)=Θ(nlogba)
- 当 f ( n ) = Θ ( n l o g b a ) f(n) = \Theta(n^{log_ba}) f(n)=Θ(nlogba)的时候, T ( n ) = Θ ( n l o g b a l g n ) T(n) = \Theta(n^{log_ba}lgn) T(n)=Θ(nlogbalgn)
- 如果有 f ( n ) = Ω ( n l o g b a + ϵ ) f(n) = \Omega(n^{log_ba + \epsilon}) f(n)=Ω(nlogba+ϵ), 且存在 c < 1 c < 1 c<1, 使得对于足够大的n有 a f ( n / b ) ≤ c f ( n ) af(n/b) \le cf(n) af(n/b)≤cf(n), T ( n ) = Θ ( f ( n ) ) T(n) = \Theta(f(n)) T(n)=Θ(f(n))
主方法的证明可以利用递归树分析完成,如果仅谈及证明而不考虑推导的话只用高中数学知识就可以完成,这里就不再赘述。
总结
本章内容介绍了递归和分治策略的思想,并且介绍了对分治策略乃至递归类算法的分析方法:递归分析法和主方法。下一章介绍代换法用于验证对本类算法的渐进分析。