分析递归式 Solving Recurrences------GeeksforGeeks 翻译
在上一章中我们讨论了如何分析循环语句。在现实中,有很多算法是递归的,当我们分析这些算法的时候我们要找到他们的的递归关系。例如归并排序,为了排序一个数组,我们把它平均分为两份然后再重复平分的步骤。最后我们合并这些结果。归并排序的时间复杂度可以写作T(n) = 2T(n/2) + cn。当然还有很多其他的类似算法如二分查找,汉诺塔等等。
有三种办法可以分析递归函数。
1.置换法 substitution method: (叫假设法比较合适)
我们可以先假设一下算法的时间复杂度,然后用数学归纳法来验证这个假设是不是正确的。
例如我们有一个这样的递归的函数 T(n) = 2T(n/2) + n 我们假设他的答案是 T(n) = O(nLogn). 现在我们用数学归纳法来验证我们的猜想 我们需要证明 存在某个常数C T(n) <= cnLogn.
我们可以假设当某个小于n的值是 这个式子是成立的 T(n) = 2T(n/2) + n <= c (n/2Log(n/2)) + n = cnLogn - cnLog2 + n = cnLogn - cn + n <= cnLogn
2.递归树的方法Recurrence Tree Method
我们可以画一个递归树并计算每一层的运行时间,最后我们把所有的时间加到一起。我们从给出的递归时开始一直往下画知道我们可以找到某种pattern。这种pattern一般都是等比数列或者等差数列
For example consider the recurrence relation T(n) = T(n/4) + T(n/2) + cn2 cn2 / \ T(n/4) T(n/2) If we further break down the expression T(n/4) and T(n/2), we get following recursion tree. cn2 / \ c(n2)/16 c(n2)/4 / \ / \ T(n/16) T(n/8) T(n/8) T(n/4) Breaking down further gives us following cn2 / \ c(n2)/16 c(n2)/4 / \ / \ c(n2)/256 c(n2)/64 c(n2)/64 c(n2)/16 / \ / \ / \ / \ To know the value of T(n), we need to calculate sum of tree nodes level by level. If we sum the above tree level by level, we get the following series T(n) = c(n^2 + 5(n^2)/16 + 25(n^2)/256) + .... The above series is geometrical progression with ratio 5/16. To get an upper bound, we can sum the infinite series. We get the sum as (n2)/(1 - 5/16) which is O(n2)
3.主定理 master method
主定理是一种可以直接得到结果的方法。但是主定理只能用于下面这种形式的递归式
T(n) = aT(n/b) + f(n) where a >= 1 and b > 1
有三种情况
1. If f(n) = Θ(nc) where c < Logba then T(n) = Θ(nlogba)
2. If f(n) = Θ(nc) where c = Logba then T(n) = Θ(ncLog n)
3.If f(n) = Θ(nc) where c > Logba then T(n) = Θ(f(n))
一些标准算法用主定理来计算时间复杂度的例子:
merge sort 归并排序 : T(n) = 2T(n/2) + Θ(n). 是第二个case c=1 Logba = 1 所以时间复杂度是 Θ(n Logn)
binary search 二分查找: T(n) = T(n/2) + Θ(1).是第二个case c=0 logba = 0 时间复杂度是Θ(Logn)