时间复杂度怎么算详解

我们假设计算机运行一行基础代码需要执行一次运算。

int aFunc(void) {printf("Hello, World!\n");      //  需要执行 1 次return 0;       // 需要执行 1 次
}

那么上面这个方法需要执行 2 次运算

int aFunc(int n) {for(int i = 0; i<n; i++) {         // 需要执行 (n + 1) 次printf("Hello, World!\n");      // 需要执行 n 次}return 0;       // 需要执行 1 次
}

这个方法需要 (n + 1 + n + 1) = 2n + 2 次运算。

我们把 算法需要执行的运算次数 用 输入大小n 的函数 表示,即 T(n) 。
此时为了 估算算法需要的运行时间 和 简化算法分析,我们引入时间复杂度的概念。

定义:存在常数 c 和函数 f(N),使得当 N >= c 时 T(N) <= f(N),表示为 T(n) = O(f(n)) 。
如图:

当 N >= 2 的时候,f(n) = n^2 总是大于 T(n) = n + 2 的,于是我们说 f(n) 的增长速度是大于或者等于 T(n) 的,也说 f(n) 是 T(n) 的上界,可以表示为 T(n) = O(f(n))。

因为f(n) 的增长速度是大于或者等于 T(n) 的,即T(n) = O(f(n)),所以我们可以用 f(n) 的增长速度来度量 T(n) 的增长速度,所以我们说这个算法的时间复杂度是 O(f(n))。

算法的时间复杂度,用来度量算法的运行时间,记作: T(n) = O(f(n))。它表示随着 输入大小n 的增大,算法执行需要的时间的增长速度可以用 f(n) 来描述。

显然如果 T(n) = n^2,那么 T(n) = O(n^2),T(n) = O(n^3),T(n) = O(n^4) 都是成立的,但是因为第一个 f(n) 的增长速度与 T(n) 是最接近的,所以第一个是最好的选择,所以我们说这个算法的复杂度是 O(n^2) 。
具体步骤
⑴ 找出算法中的基本语句;

算法中执行次数最多的那条语句就是基本语句,通常是最内层循环的循环体。

⑵ 计算基本语句的执行次数的数量级;

只需保留f(n)中的最高次幂正确即可,可以忽略所有低次幂和最高次幂的系数。

⑶ 用大Ο记号表示算法的时间性能。

将基本语句执行次数的数量级放入大Ο记号中。

举例

  1. 对于一个循环,假设循环体的时间复杂度为 O(n),循环次数为 m,则这个循环的时间复杂度为 O(n×m)。
void aFunc(int n) {for(int i = 0; i < n; i++) {         // 循环次数为 nprintf("Hello, World!\n");      // 循环体时间复杂度为 O(1)}
}

此时时间复杂度为 O(n × 1),即 O(n)。

2.对于多个循环,假设循环体的时间复杂度为 O(n),各个循环的循环次数分别是a, b, c…,则这个循环的时间复杂度为O(n×a×b×c…)。分析的时候应该由里向外分析这些循环。

void aFunc(int n) {for(int i = 0; i < n; i++) {         // 循环次数为 nfor(int j = 0; j < n; j++) {       // 循环次数为 nprintf("Hello, World!\n");      // 循环体时间复杂度为 O(1)}}
}

此时时间复杂度为 O(n × n × 1),即 O(n^2)。

  1. 对于顺序执行的语句或者算法,总的时间复杂度等于其中最大的时间复杂度。
void aFunc(int n) {// 第一部分时间复杂度为 O(n^2)for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) {printf("Hello, World!\n");}}// 第二部分时间复杂度为 O(n)for(int j = 0; j < n; j++) {printf("Hello, World!\n");}
}
此时时间复杂度为 max(O(n^2), O(n)),即 O(n^2)。
  1. 对于条件判断语句,总的时间复杂度等于其中 时间复杂度最大的路径 的时间复杂度。
void aFunc(int n) {if (n >= 0) {// 第一条路径时间复杂度为 O(n^2)for(int i = 0; i < n; i++) {for(int j = 0; j < n; j++) {printf("输入数据大于等于零\n");}}} else {// 第二条路径时间复杂度为 O(n)for(int j = 0; j < n; j++) {printf("输入数据小于零\n");}}
}

此时时间复杂度为 max(O(n^2), O(n)),即 O(n^2)。

时间复杂度分析的基本策略是:从内向外分析,从最深层开始分析。如果遇到函数调用,要深入函数进行分析。

练习
1.

void aFunc(int n) {for (int i = 0; i < n; i++) {for (int j = i; j < n; j++) {printf("Hello World\n");}}
}

当 i = 0 时,内循环执行 n 次运算,当 i = 1 时,内循环执行 n - 1 次运算……当 i = n - 1 时,内循环执行 1 次运算。
所以,执行次数 T(n) = n + (n - 1) + (n - 2)……+ 1 = n(n + 1) / 2 = n^2 / 2 + n / 2。
根据上文说的 大O推导法 可以知道,此时时间复杂度为 O(n^2)。

void aFunc(int n) {for (int i = 2; i < n; i++) {i *= 2;printf("%i\n", i);}
}

假设循环次数为 t,则循环条件满足 2^t < n。
可以得出,执行次数t = log(2)(n),即 T(n) = log(2)(n),可见时间复杂度为 O(log(2)(n)),即 O(log n)。

long aFunc(int n) {if (n <= 1) {return 1;} else {return aFunc(n - 1) + aFunc(n - 2);}
}

显然运行次数,T(0) = T(1) = 1,同时 T(n) = T(n - 1) + T(n - 2) + 1,这里的 1 是其中的加法算一次执行。
显然 T(n) = T(n - 1) + T(n - 2) 是一个斐波那契数列,通过归纳证明法可以证明,当 n >= 1 时 T(n) < (5/3)^n,同时当 n > 4 时 T(n) >= (3/2)^n。
所以该方法的时间复杂度可以表示为 O((5/3)^n),简化后为 O(2^n)。

时间复杂度分析的基本策略是:从内向外分析,从最深层开始分析。如果遇到函数调用,要深入函数进行分析。

时间复杂度怎么算详解相关推荐

  1. 虫食算-详解-noip2004-深搜

    虫食算 网址:https://vijos.org/p/1099 描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865# ...

  2. 时间复杂度的计算详解

    时间复杂度计算分为以下三个步骤(推导大O阶): 1.用常数1取代运行时间中的所有加法常数 2.在修改后的运行次数函数中,只保留最高阶项 3.如果最高阶项存在且不是1,则去除与这个项相乘的常数,得到的结 ...

  3. 【数据结构入门】算法的时间复杂度和空间复杂度详解

    文章目录 (1)算法效率 (2)时间复杂度的计算 1)什么是时间复杂度 2)大O渐进表示法(估算) 3)时间复杂度计算实例 4)总结 5)一些思考 (3)空间复杂度的计算 (4)常见复杂度对比 本篇前 ...

  4. Java——时间复杂度、空间复杂度详解

    复杂度 算法效率 时间复杂度 什么是时间复杂度 推导大 O 阶的方法 算法情况 计算冒泡排序的时间复杂度 计算二分查找的时间复杂度 计算阶乘递归的时间复杂度 计算斐波那契递归的时间复杂度 空间复杂度 ...

  5. 算法时间复杂度和空间复杂度详解

    1.算法的概念: 算法 (Algorithm),是对特定问题求解步骤的一种描述. 解决一个问题往往有不止一种方法,算法也是如此.那么解决特定问题的多个算法之间如何衡量它们的优劣呢?有如下的指标: 2. ...

  6. 时间复杂度(超详解+例题)

    全文目录 引言 如何衡量一个算法的好坏 时间复杂度 时间复杂度的定义 时间复杂度的大O表示法 实例 test1 test2 test3 test4 test5 总结 引言 如何衡量一个算法的好坏 我们 ...

  7. 斐波那契数的时间复杂度、空间复杂度详解

     斐波那契数:斐波那契数列指的是1.1.2.3.5.8.13.21.······这样一个数列,我们可以发现它后面的一个数是前两个数之和.而在这个数列中的数就被称为斐波那契数. 时间复杂度:时间复杂 ...

  8. 【51单片机 】定时器的初始值计算 详解

    首先值得一提的是:51单片机定时器与主程序是并行工作的,就是主程序在运行的时候,定时器也在计数,计数溢出后定时器中断主程序的运行,转而执行中断服务程序.此外还有串行口.中断系统-,都独立的工作,不用 ...

  9. 时间复杂度和空间复杂度详解带例题(精)

    算法 算法(Algorithm)是指用来操作数据.解决程序问题的一组方法.对于同一个问题,使用不同的算法,也许最终得到的结果是一样的,但在过程中消耗的资源和时间却会有很大的区别. 那么我们应该如何去衡 ...

最新文章

  1. C++ open 打开文件(含打开模式一览表)
  2. k中心点聚类算法伪代码_聚类算法之——K-Means、Canopy、Mini Batch K-Means
  3. AtCoder AGC030F Permutation and Minimum (DP、计数)
  4. boost::mpl模块实现list相关的测试程序
  5. eclipse中护眼色设置
  6. PostgreSQL per database or per user audit use pg_log_userqueries
  7. RAID (HP)双循环
  8. 《道德经》「人法地 地法天 天法道 道法自然」
  9. 重庆工程学院计算机设计大赛获奖名单,重大城科学子在2018年(第11届)中国大学生计算机设计大赛全国总决赛获一等奖...
  10. was compiled with optimization - stepping may behave oddly; variables may not be available.
  11. Tableau数据分析笔记-Chapter06填充地图、多维地图、混合地图
  12. WCE 电源管理器(开胃菜)
  13. lm283_BP283X 最小输入输出压差和OVP电压的关系
  14. python 双重差分_双重差分的理论与实践
  15. 【论文解读 WWW 2019 | HAN】Heterogeneous Graph Attention Network
  16. 视频教程-MMOARPG地下守护神_单机版实战视频课程(下部) -Unity3D
  17. HDU 2005 第几天?
  18. 苹果手机悬浮窗怎么打开_悬浮窗搜题神器_悬浮窗搜题神器app源码苹果软件预约 v1.0...
  19. transferto方法的应用_NIO的transferTo方法
  20. SAP 租户HANA端口查询以及创建数据库指定端口

热门文章

  1. OOM问题排查及原因解析
  2. 基于JavaWeb的党员管理系统
  3. group conv 和 depthwise conv
  4. 如何删除 AppStore 中的恶意评论 iOS
  5. RSSI CSQ 转换函数
  6. 流体时间,水波纹效果
  7. c# web PDF 转图片总结
  8. vpp 版本选择_苹果VPP协议中文版
  9. 1.STM32基本知识
  10. 利用Xshell+Proxifier实现全局代理上网