递归算法复杂度Ω分析-分享

1. 深入认识递归 (1) 递归执行过程 例子:求N!。 这是一个简单的"累乘"问题,用递归算法也能解决。 n! = n * (n - 1)! n > 1 0! = 1, 1! = 1 n = 0,1 因此,递归算法如下:

Java代码

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

以n=3为例,看运行过程如下: fact(3) ----- fact(2) ----- fact(1) ------ fact(2) -----fact(3) ------------------------------> ------------------------------> 递归 回溯

递归算法在运行中不断调用自身降低规模的过程,当规模降为1,即递归到fact(1)时,满足停止条件停止递归,开始回溯(返回调用算法)并计算,从fact(1)=1计算返回到fact(2);计算2*fact(1)=2返回到fact(3);计算3*fact(2)=6,结束递归。 算法的起始模块也是终止模块。 (2) 递归实现机制

每一次递归调用,都用一个特殊的数据结构"栈"记录当前算法的执行状态,特别地设置地址栈,用来记录当前算法的执行位置,以备回溯时正常返回。递归模块的形式参数是普通变量,每次递归调用得到的值都是不同的,他们也是由"栈"来存储。 (3) 递归调用的几种形式 一般递归调用有以下几种形式(其中a1、a2、b1、b2、k1、k2为常数)。 <1> 直接简单递归调用: f(n) {...a1 * f((n - k1) / b1); ...}; <2> 直接复杂递归调用: f(n) {...a1 * f((n - k1) / b1); a2 * f((n - k2) / b2); ...}; <3> 间接递归调用: f(n) {...a1 * f((n - k1) / b1); ...}, g(n) {...a2 * f((n - k2) / b2); ...}。 2. 递归算法效率分析方法 递归算法的分析方法比较多,最常用的便是迭代法。 迭代法的基本步骤是先将递归算法简化为对应的递归方程,然后通过反复迭代,将递归方程的右端变换成一个级数,最后求级数的和,再估计和的渐进阶。

<1> 例:n! 算法的递归方程为: T(n) = T(n - 1) + O(1); 迭代展开: T(n) = T(n - 1) + O(1) = T(n - 2) + O(1) + O(1) = T(n - 3) + O(1) + O(1) + O(1) = ...... = O(1) + ... + O(1) + O(1) + O(1) = n * O(1) = O(n) 这个例子的时间复杂性是线性的。 <2> 例:如下递归方程: T(n) = 2T(n/2) + 2, 且假设n=2的k次方。 T(n) = 2T(n/2) + 2 = 2(2T(n/2*2) + 2) + 2 = 4T(n/2*2) + 4 + 2 = 4(2T(n/2*2*2) + 2) + 4 + 2 = 2*2*2T(n/2*2*2) + 8 + 4 + 2 = ... = 2的(k-1)次方 * T(n/2的(i-1)次方) + $(i:1~(k-1))2的i次方 = 2的(k-1)次方 + (2的k次方) - 2 = (3/2) * (2的k次方) - 2 = (3/2) * n - 2 = O(n) 这个例子的时间复杂性也是线性的。 <3> 例:如下递归方程: T(n) = 2T(n/2) + O(n), 且假设n=2的k次方。 T(n) = 2T(n/2) + O(n) = 2T(n/4) + 2O(n/2) + O(n) = ... = O(n) + O(n) + ... + O(n) + O(n) + O(n) = k * O(n) = O(k*n) = O(nlog2n) //以2为底 一般地,当递归方程为T(n) = aT(n/c) + O(n), T(n)的解为: O(n) (a<c && c>1) O(nlog2n) (a=c && c>1) //以2为底 O(nlogca) (a>c && c>1) //n的(logca)次方,以c为底 上面介绍的3种递归调用形式,比较常用的是第一种情况,第二种形式也有时出现,而第三种形式(间接递归调用)使用的较少,且算法分析比较复杂。 下面举个第二种形式的递归调用例子。 <4> 递归方程为:T(n) = T(n/3) + T(2n/3) + n 为了更好的理解,先画出递归过程相应的递归树:

n --------> n n/3 2n/3 --------> n n/9 2n/9 2n/9 4n/9 --------> n ...... ...... ...... ....... ...... -------- 总共O(nlogn) 累计递归树各层的非递归项的值,每一层和都等于n,从根到叶的最长路径是: n --> (2/3)n --> (4/9)n --> (12/27)n --> ... --> 1 设最长路径为k,则应该有: (2/3)的k次方 * n = 1 得到 k = log(2/3)n // 以(2/3)为底 于是 T(n) <= (K + 1) * n = n (log(2/3)n + 1) 即 T(n) = O(nlogn) 由此例子表明,对于第二种递归形式调用,借助于递归树,用迭代法进行算法分析是简单易行的。

原文发布于微信公众号 - ACM算法日常(acm-clan)

原文发表时间:2018-06-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏余林丰

2.比较排序之梳排序

  梳排序的知名度远没有其他排序算法那么高,它是在冒泡排序的基础上做的改进,引入类似“步长”以及“子序列”概念,这两个概念在后面的排序算法中会经常提及。   待...

22180
来自专栏我是业余自学C/C++的

矩阵

14450
来自专栏人工智能头条

70个NumPy练习:在Python下一举搞定机器学习矩阵运算

32720
来自专栏Python攻城狮

科学计算工具Numpy1.ndarray的创建与数据类型2.ndarray的矩阵运算ndarray的索引与切片3.ndarray的元素处理元素判断函数元素去重排序函数4.2016年美国总统大选民意调查

Numpy:提供了一个在Python中做科学计算的基础库,重在数值计算,主要用于多维数组(矩阵)处理的库。用来存储和处理大型矩阵,比Python自身的嵌套列表结...

28230
来自专栏Python小屋

Python高级数组处理模块numpy用法精要

numpy是Python的高级数组处理扩展库,提供了Python中没有的数组对象,支持N维数组运算、处理大型矩阵、成熟的广播函数库、矢量运算、线性代数、傅里叶变...

50270
来自专栏Python小屋

使用Python列表实现向量运算

在Python中,列表支持与整数的乘法运算,但表示的是列表元素的重复,并生成新列表,如: >>> [1,2,3]*3 [1, 2, 3, 1, 2, 3, 1...

60960
来自专栏Python绿色通道

Numpy归纳整理

说明本文主要是关于Numpy的一些总结,包括他们的一些运算公式,我整理一下方便日后查阅公式!

16320
来自专栏chenjx85的技术专栏

leetcode-33-搜索旋转排序数组

( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

12330
来自专栏desperate633

LintCode 搜索旋转排序数组题目分析代码

假设有一个排序的按未知的旋转轴旋转的数组(比如,0 1 2 4 5 6 7 可能成为4 5 6 7 0 1 2)。给定一个目标值进行搜索,如果在数组中找到目标值...

10820
来自专栏软件开发 -- 分享 互助 成长

二维数组简介与使用

前言 本文将探讨一下关于二维数组在内存中的存储和二维数组在参数传递时的使用。 一、二维数组在内存中的存储 如果定义一个这样的二维数组int a[3][4]={{...

253100

扫码关注云+社区

领取腾讯云代金券