递归算法中的时间复杂度分析

对于一种算法的时间复杂度分析还是特别重要的,在一些非递归算法中,我们仅仅看运算次数最多的那一行代码可能执行多少次就可以,实际就是看在循环中变量的变化,但是对于递归算法中该怎么分析呢?下面介绍几种递归函数中的算法时间复杂度分析的方法

0.递推法

这种方法是最简单的,也是最容易理解的一种方法,对于一个递归函数,我们可以利用他的递归方程,将其递推到常量的情况下,这样子就很容易求解他的时间复杂度了,可以看一下下面的递归方程
T ( n ) = { 1 n = 1 T ( n − 1 ) + 1 n > 0 T(n) = \left\{\begin{matrix} 1 \qquad n=1\\ T(n-1)+1 \qquad n>0 \end{matrix}\right. T(n)={1n=1T(n1)+1n>0
我们可以递归成
T ( n ) = T ( n − 1 ) + 1 = T ( n − 2 ) + 2 = T ( n − 3 ) + 3 = . . . = T ( 1 ) + n − 1 T(n)= T(n-1)+1 = T(n-2) +2 = T(n-3)+3=...=T(1)+ n-1 T(n)=T(n1)+1=T(n2)+2=T(n3)+3=...=T(1)+n1
这样很容易就可以看出来这个上面这个递归算法的时间复杂度是O(n)

这种方法思路比较简单,但是使用的时候会特别复杂,上面举的例子是一种比较简单的情况,要是比较复杂的情况这种就会很麻烦。

1.Master定理

master定理又称为主定理,这是一种快速的得出递归函数的时间复杂度

下面看一下,主定理的内容:

对于任意的递归函数,我们都一可以写出他的递归定义,下面我们给出递归定义的一般形式:
T ( n ) = { O ( 1 ) n = n 0 a T ( n b ) + f ( n ) n > n 0 T(n) = \left\{\begin{matrix} O(1) \qquad n=n0\\ aT(\frac{n}{b})+f(n) \qquad n>n0 \end{matrix}\right. T(n)={O(1)n=n0aT(bn)+f(n)n>n0
这里要是a>=1,b>1,并且f(n)是正函数

使用主定理方法,就是比较两个公式阶的比较 n log ⁡ b a n^{\log_{b}{a} } nlogba f ( n ) f(n) f(n),已求出T(n)的时间复杂度。

规则1:如果 f ( n ) = O ( n log ⁡ b a − ε ) f(n) = O(n^{\log_{b}{a-\varepsilon } } ) f(n)=O(nlogbaε) 其中 ε \varepsilon ε >0 为常数,也就是说 f ( n ) < O ( n log ⁡ b a ) f(n) < O(n^{\log_{b}{a} } ) f(n)<O(nlogba) ,则 T ( n ) = O ( n log ⁡ b a ) T(n) = O(n^{\log_{b}{a} } ) T(n)=O(nlogba)

规则2:如果 f ( n ) = Θ ( n log ⁡ b a ) f(n) = \Theta (n^{\log_{b}{a} } ) f(n)=Θ(nlogba) ,则 T ( n ) = O ( n log ⁡ b a log ⁡ n ) T(n) = O(n^{\log_{b}{a} } \log_{}{n} ) T(n)=O(nlogbalogn)

规则3:如果 f ( n ) = Ω ( n log ⁡ b a + ε ) f(n) = \Omega (n^{\log_{b}{a+\varepsilon } } ) f(n)=Ω(nlogba+ε) 其中 ε \varepsilon ε >0 为常数,也就是说 f ( n ) > O ( n log ⁡ b a ) f(n) > O(n^{\log_{b}{a } } ) f(n)>O(nlogba) 且存在n0,当n>n0时, a f ( n b ) ≤ c f ( n ) af(\frac{n}{b} )\le cf(n) af(bn)cf(n) 成立,c<1为常数,则 T ( n ) = O ( f ( n ) ) T(n) = O(f(n) ) T(n)=O(f(n))

以上就是主定理的内容,我们可以根据其规则直接快速的来判断递归函数的时间复杂度。

下面举个栗子看一看主定理的使用:

例一:

下面这个是一个时间复杂度的递归定义:
T ( n ) = { 1 n = 1 4 T ( n 2 ) + 1 n > 1 T(n) = \left\{\begin{matrix} 1 \qquad n=1\\ 4T(\frac{n}{2})+1 \qquad n>1 \end{matrix}\right. T(n)={1n=14T(2n)+1n>1
根据在主定理规则,我们先写出 n log ⁡ b a n^{\log_{b}{a} } nlogba f ( n ) f(n) f(n) n log ⁡ b a n^{\log_{b}{a} } nlogba = n log ⁡ 2 4 n^{\log_{2}{4} } nlog24 = n 2 n^{2} n2 f ( n ) = 1 f(n) = 1 f(n)=1 。很明显这里对于阶数的比较

n log ⁡ b a > f ( n ) n^{\log_{b}{a} } > f(n) nlogba>f(n),所以根据主定理规则, T ( n ) = O ( n log ⁡ b a ) T(n) = O(n^{\log_{b}{a} } ) T(n)=O(nlogba) ,即 T ( n ) = O ( n 2 ) T(n) = O(n^{2} ) T(n)=O(n2)

例二:

下面这个是一个时间复杂度的递归定义:
T ( n ) = { 1 n = 1 2 T ( n 2 ) + n n > 1 T(n) = \left\{\begin{matrix} 1 \qquad n=1\\ 2T(\frac{n}{2})+n \qquad n>1 \end{matrix}\right. T(n)={1n=12T(2n)+nn>1
根据在主定理规则,我们先写出 n log ⁡ b a n^{\log_{b}{a} } nlogba f ( n ) f(n) f(n) n log ⁡ b a n^{\log_{b}{a} } nlogba = n log ⁡ 2 2 n^{\log_{2}{2} } nlog22 = n n n f ( n ) = n f(n) =n f(n)=n 。很明显这里对于阶数的比较

n log ⁡ b a = f ( n ) n^{\log_{b}{a} } = f(n) nlogba=f(n),所以根据主定理规则, T ( n ) = O ( n log ⁡ b a log ⁡ n ) ) T(n) = O(n^{\log_{b}{a} } \log_{}{n} )) T(n)=O(nlogbalogn)) ,即 T ( n ) = O ( n log ⁡ n ) T(n) = O(n\log_{}{n} ) T(n)=O(nlogn)

例三:

下面这个是一个时间复杂度的递归定义:
T ( n ) = { 1 n = 1 4 T ( n 2 ) + n 3 n > 1 T(n) = \left\{\begin{matrix} 1 \qquad n=1\\ 4T(\frac{n}{2})+n^{3} \qquad n>1 \end{matrix}\right. T(n)={1n=14T(2n)+n3n>1
根据在主定理规则,我们先写出 n log ⁡ b a n^{\log_{b}{a} } nlogba f ( n ) f(n) f(n) n log ⁡ b a n^{\log_{b}{a} } nlogba = n log ⁡ 2 4 n^{\log_{2}{4} } nlog24 = n 2 n^{2} n2 f ( n ) = n 3 f(n) =n^{3} f(n)=n3 。很明显这里对于阶数的比较

n log ⁡ b a < f ( n ) n^{\log_{b}{a} } < f(n) nlogba<f(n),有 4 f ( n 2 ) ≤ c f ( n ) 4f(\frac{n}{2} )\le cf(n) 4f(2n)cf(n) ,是否存在c使得这个式子成立, 4 f ( n 2 ) = 4 ( n 2 ) 3 < c n 3 4f(\frac{n}{2} )=4(\frac{n}{2})^{3} < cn^{3} 4f(2n)=4(2n)3<cn3,很显然 1 2 < c < 1 \frac{1}{2} < c <1 21<c<1,这里的所以根据主定理规则, T ( n ) = O ( f ( n ) ) T(n) = O(f(n)) T(n)=O(f(n)),即
T ( n ) = O ( n 3 ) T(n) = O(n^{3} ) T(n)=O(n3)
这就是上面三种情况,我们也很容易的发现,在第三种规则的时候多了一个判定的条件,如果这个条件不满足那么就不能使用主定理这个方法了。看下面的一个例子:

下面这个是一个时间复杂度的递归定义:
T ( n ) = { 1 n = 1 2 T ( n 2 ) + n log ⁡ n n > 1 T(n) = \left\{\begin{matrix} 1 \qquad n=1\\ 2T(\frac{n}{2})+n\log_{}{n} \qquad n>1 \end{matrix}\right. T(n)={1n=12T(2n)+nlognn>1
根据主定理的规则,我们同样先写出他的 n log ⁡ b a n^{\log_{b}{a} } nlogba f ( n ) f(n) f(n) n log ⁡ b a n^{\log_{b}{a} } nlogba = n log ⁡ 2 2 n^{\log_{2}{2} } nlog22 = n n n f ( n ) = n log ⁡ n f(n) =n\log_{}{n} f(n)=nlogn ,显然 n log ⁡ b a < f ( n ) n^{\log_{b}{a} } < f(n) nlogba<f(n) 这就符合规则三,但是我们还要判断一下是否存在一个 ε \varepsilon ε 使得 f ( n ) = Ω ( n log ⁡ b a + ε ) f(n) = \Omega (n^{\log_{b}{a+\varepsilon } } ) f(n)=Ω(nlogba+ε) 成立,显然是不存在 ε \varepsilon ε的,所以该题目不适应主定理。

2.递归树

递归树的这种解法,其实跟递推的方法其实很相似,就是根据树的形式来确定时间的复杂度。我们之间来看个例子:

下面这个是一个时间复杂度的递归定义:
T ( n ) = { 1 n = 1 2 T ( n 2 ) + n n > 1 T(n) = \left\{\begin{matrix} 1 \qquad n=1\\ 2T(\frac{n}{2})+n \qquad n>1 \end{matrix}\right. T(n)={1n=12T(2n)+nn>1
我们可以很容易的画出他的递归树来,以他的f(n)为根,并以他的递归方程形式,分成孩子结点
递归算法中的时间复杂度分析_第1张图片

我们通过观察这个递归树可以发现,每一层消耗的时间都是n,那么只要知道这课递归树的高度,我们就可以大致的判断出这个递归算法的时间复杂度,实际就是求出这颗树中结点的个数。很容易的可以看出来,这棵树是一颗满二叉树,那么他的高度应该为 log ⁡ 2 n \log_{2}{n} log2n,这就很容易判断出这个递归算法的时间复杂度为 O ( n log ⁡ n ) O(n \log_{}{n} ) O(nlogn)

你可能感兴趣的:(数据结构与算法,算法,二叉树,数据结构)