文章目录

  • 前言
  • 1 时间复杂度
    • 1.1 分析方法
    • 1.2 常见时间复杂度
    • 2.3 最坏时间复杂度、最好时间复杂度、平均时间复杂度
  • 2.空间复杂度

前言

学习数据结构和算法,并不是为了死记硬背几个知识点。我们的目的是建立时间复杂度、空间复杂度意识,写出高质量的代码,能够设计基础架构,提升编程技能,训练逻辑思维,积攒人生经验,以此获得工作回报,实现你的价值,完善你的人生。
       掌握了数据结构与算法,你看待问题的深度,解决问题的角度就会完全不一样。因为这样的你,就像是站在巨人的肩膀上,拿着生存利器行走世界。数据结构与算法,会为你的编程之路,甚至人生之路打开一扇通往新世界的大门。

对数据结构和算法,要学习它的来历、自身的特点、适合解决的问题和实际的应用场景
最常用的、最基础数据结构与算法:
10 个数据结构:数组、链表、栈、队列、散列表、二叉树、堆、跳表、图、Trie 树;
10 个算法:递归、排序、二分查找、搜索、哈希算法、贪心算法、分治算法、回溯算法、动态规划、字符串匹配算法。

我们需要一个不用具体测试就可以粗略地估计算法的执行效率的方法。这就是时间、空间复杂度分析方法,即大 O 复杂度表示法。

1 时间复杂度

所有代码的执行时间 T(n) 与每行代码的执行次数 n 成正比,因此我们用T(n) = O(f(n))来表示代码执行时间,即大 O 时间复杂度表示法。
       大O 时间复杂度实际上并不具体表示代码真正的执行时间,而是表示代码执行时间随数据规模增长的变化趋势。n 很大时,你可以把它想象成 10000、100000。而公式中的低阶、常量、系数三部分并不左右增长趋势,所以都可以忽略。我们只需要记录一个最大量级就可以了。

1.1 分析方法

  1. 只关注循环执行次数最多的一段代码
 int cal(int n) {int sum = 0;int i = 1;for (; i <= n; ++i) {sum = sum + i;}return sum;}

其中第 2、3 行代码都是常量级的执行时间,与 n 的大小无关,所以对于复杂度并没有影响。循环执行次数最多的是第 4、5 行代码,所以这块代码要重点分析。前面我们也讲过,这两行代码被执行了 n 次,所以总的时间复杂度就是 O(n)。

  1. 总复杂度等于量级最大的那段代码的复杂度
int cal(int n) {int sum_1 = 0;int p = 1;for (; p < 100; ++p) {sum_1 = sum_1 + p;}int sum_2 = 0;int q = 1;for (; q < n; ++q) {sum_2 = sum_2 + q;}int sum_3 = 0;int i = 1;int j = 1;for (; i <= n; ++i) {j = 1; for (; j <= n; ++j) {sum_3 = sum_3 +  i * j;}}return sum_1 + sum_2 + sum_3;}

这个代码分为三部分,分别是求 sum_1、sum_2、sum_3。我们可以分别分析每一部分的时间复杂度,然后把它们放到一块儿,再取一个量级最大的作为整段代码的复杂度。
       第一段的时间复杂度是多少呢?这段代码循环执行了 100 次,所以是一个常量的执行时间,跟 n 的规模无关。这里再强调一下,即便这段代码循环 10000 次、100000 次,只要是一个已知的数,跟 n 无关,照样也是常量级的执行时间。当 n 无限大的时候,就可以忽略。尽管对代码的执行时间会有很大影响,但是回到时间复杂度的概念来说,它表示的是一个算法执行效率与数据规模增长的变化趋势,所以不管常量的执行时间多大,我们都可以忽略掉。因为它本身对增长趋势并没有影响。
       那第二段代码和第三段代码的时间复杂度是 O(n) 和 O(n2)。综合这三段代码的时间复杂度,我们取其中最大的量级。所以整段代码的时间复杂度就为 O(n2)。也就是说:总的时间复杂度就等于量级最大的那段代码的时间复杂度 。

  1. 嵌套代码的复杂度等于嵌套内外代码复杂度的乘积

    int cal(int n) {int ret = 0; int i = 1;for (; i < n; ++i) {ret = ret + f(i);} } int f(int n) {int sum = 0;int i = 1;for (; i < n; ++i) {sum = sum + i;} return sum;}
    

我们单独看 cal() 函数。假设 f() 只是一个普通的操作,那第 4~6 行的时间复杂度就是T1(n) = O(n)。但 f() 函数本身不是一个简单的操作,它的时间复杂度是 T2(n) = O(n),所以,整个 cal() 函数的时间复杂度就是,T(n) = T1(n) * T2(n) = O(n*n) = O(n2)。

1.2 常见时间复杂度

  1. 常量级 O(1)
    只要代码的执行时间不随 n 的增大而增长,这样代码的时间复杂度我们都记作 O(1)。或者说一般情况下,只要算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)。

  2. 对数阶 O(logn)
    对数阶时间复杂度非常常见,同时也是最难分析的一种时间复杂度。

     i=1;while (i <= n)  {i = i * 2;}
    

    其实相当于求解 2x=n 中 x的值, 也就是x=log2n,所以这段代码的时间复杂度就是 O(log2n)。

      i=1;while (i <= n) {i = i * 3; }
    

很简单就能看出来,这段代码的时间复杂度为 O(log3n)。实际上,不管是以 2 为底、以 3 为底,还是以 10 为底,我们可以把所有对数阶的时间复杂度都记为 O(logn)。为什么呢?我们知道,对数之间是可以互相转换的,log3n 就等于 log32 * log2n,所以 O(log3n) = O(C * log2n),其中 C=log32 是一个常量。基于我们前面的一个理论:在采用大 O 标记复杂度的时候,可以忽略系数,即 O(Cf(n)) = O(f(n))。所以,O(log2n) 就等于 O(log3n)。因此,在对数阶时间复杂度的表示方法里,我们忽略对数的“底”,统一表示为 O(logn)。

  1. O(n)

  2. O(nlogn)
    像快排的时间复杂度就是O(nlogn)。

    public static void quickSort(int[] arr, int left, int right) {// 结束递归的条件if (left > right) {return;}int temp;int i = left;int j = right;int baseNum = arr[left];//开始循环寻找while (i != j) {while (j > i && arr[j] > baseNum) {j--;}while (i < j && arr[i] <= baseNum) {i++;}//此时说明停下来,交换两个数位置temp = arr[i];arr[i] = arr[j];arr[j] = temp;}//跳出while循环说明两个指针相遇,此时基准数归位arr[left] = arr[i];arr[i] = baseNum;//继续递归调用quickSort(arr, left, i - 1);quickSort(arr, i + 1, right);}
    
  3. n2、n3、nk等k次方阶

  4. 指数阶O(2n) 、 阶乘阶O(n!)
    这两个属于非多项式量级,我们把时间复杂度为非多项式量级的算法问题叫作 NP(Non-Deterministic Polynomial,非确定多项式)问题。非多项式时间复杂度的算法其实是非常低效的算法,一般很少遇到。

  5. O(m+n)、O(m*n)
    从下面代码中可以看出,m 和 n 是表示两个数据规模。我们无法事先评估 m 和 n 谁的量级大,所以我们在表示复杂度的时候,就不能简单地利用加法法则,省略掉其中一个。所以下面代码的时间复杂度就是 O(m+n)。

    int cal(int m, int n) {int sum_1 = 0;int i = 1;for (; i < m; ++i) {sum_1 = sum_1 + i;}int sum_2 = 0;int j = 1;for (; j < n; ++j) {sum_2 = sum_2 + j;}return sum_1 + sum_2;
    }
    

2.3 最坏时间复杂度、最好时间复杂度、平均时间复杂度

顾名思义,最好情况时间复杂度就是,在最理想的情况下,执行这段代码的时间复杂度。同理,最坏情况时间复杂度就是,在最糟糕的情况下,执行这段代码的时间复杂度。
       而平均时间复杂度实际上在概率论中,应该叫加权平均时间复杂度或者期望时间复杂度。很多时候,我们使用一个复杂度就可以满足需求了。只有同一块代码在不同的情况下,时间复杂度有量级的差距,我们才会使用这三种复杂度表示法来区分。
       均摊时间复杂度,对一个数据结构进行一组连续操作中,大部分情况下时间复杂度都很低,只有个别情况下时间复杂度比较高,而且这些操作之间存在前后连贯的时序关系,这个时候,我们就可以将这一组操作放在一块儿分析,看是否能将较高时间复杂度那次操作的耗时平摊到其他那些时间复杂度比较低的操作上。而且,在能够应用均摊时间复杂度分析的场合,一般均摊时间复杂度就等于最好情况时间复杂度。

2.空间复杂度

表示算法的存储空间与数据规模之间的增长关系

void print(int n) {int i = 0;int[] a = new int[n];for (i; i <n; ++i) {a[i] = i * i;}for (i = n-1; i >= 0; --i) {print out a[i]}
}

跟时间复杂度分析一样,我们可以看到第 2 行代码中,我们申请了一个空间存储变量 i,但是它是常量阶的,跟数据规模 n 没有关系,所以我们可以忽略。第 3 行申请了一个大小为 n 的 int 类型数组,除此之外,剩下的代码都没有占用更多的空间,所以整段代码的空间复杂度就是 O(n)。
       我们常见的空间复杂度就是 O(1)、O(n)、O(n2),像 O(logn)、O(nlogn) 这样的对数阶复杂度平时都用不到。

数据结构和算法之时间复杂度相关推荐

  1. 数据结构与算法之时间复杂度详解

    数据结构与算法之时间复杂度详解 目录 排序算法的介绍和分类 算法的时间复杂度概念 常见的时间复杂度解析 平均时间复杂度和最坏时间复杂度 空间复杂度介绍 1. 排序算法的介绍和分类 排序算法的介绍 排序 ...

  2. 数据结构与算法之时间复杂度与空间复杂度

    ⭐️前面的话⭐️ 本篇文章带大家认识数据结构与算法基础,时间复杂度与空间复杂度.算法效率分析分为两种:第一种是时间效率,第二种是空间效率.时间效率被称为时间复杂度,而空间效率被称作空间复杂度. 时间复 ...

  3. 【数据结构与算法】时间复杂度和空间复杂度

    文章目录 前言 数据结构与算法 如何学好数据结构和算法 算法效率 算法的复杂度 时间复杂度 大O的渐进表示法 空间复杂度 常见复杂度对比 OJ练习题 消失的数字 轮转数组 结语 前言 大家好哦,< ...

  4. 【数据结构和算法】时间复杂度和空间复杂度

    目录 一.前言 二.时间复杂度 2.1时间复杂度表示形式 2.1.1规则: 3.1如何计算时间复杂度 3.1.1线性阶 3.1.2平方阶 3.1.3对数阶 常见的时间复杂度排序: 三.空间复杂度 3. ...

  5. 数据结构与算法-常见时间复杂度

    参考链接: 算法的时间复杂度和空间复杂度 - 简书 https://www.jianshu.com/p/88a1c8ed6254 常见时间复杂度 时间复杂度曲线 关于log > 如果a^b=c, ...

  6. 数据结构和算法———P3 时间复杂度和空间复杂度

    算法效率的度量方法 算法时间复杂度的定义: 在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级.算法的时间复杂度,也就是算法的时间度 ...

  7. 【数据结构】算法的时间复杂度和空间复杂度解析

    目录 1. 算法的效率 2 时间复杂度 2.1 时间复杂度的概念 2.2 大O渐进表示法 2.3 常见算法的时间复杂度分析 3. 空间复杂度 3.1 常见空间复杂度分析 1. 算法的效率 我们在写一个 ...

  8. 数据结构: 算法的时间复杂度和空间复杂度

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

  9. 二、考研数据结构笔记——绪论(理解数据结构,算法,时间复杂度计算做题技巧)

    一.数据结构基本概念 1.数据:数据是信息的载体.客观事物的一种表现形式.万事万物都能用数据表示出来. 2.数据元素:数据元素是数据的基本单位,一个数据元素有若干个数据项组成 3.数据项:构成数据元素 ...

最新文章

  1. 仿WINDWS无限级Ajax菜单树升级1.2版(菜单名支持非法字符)
  2. Android踩坑日记:Android动态权限分析和解决方案
  3. flutter 版本控制fvm
  4. hdu 5274(树链剖分)
  5. 写毕业论文的最容易踩的几个坑
  6. C语言十进制数转换为八进制(附完整源码)
  7. 可变参数列表(va_list,va_arg,va_copy,va_start,va_end)
  8. 7-2 作业调度算法--短作业优先 (30 分)(思路+详解+vector容器做法)Come Baby!!!!!!!!!!!
  9. 基本程序单元Activity—Activity生命周期之数据传递小程序
  10. 手把手教你编写Logstash插件
  11. web 前端 如何分享到instagram_面对前端的后端化趋势,2020该如何学习web前端?
  12. RESTful API 特点
  13. 携程否认竞价排名;戴尔为“吃鸡外挂”致歉;腾讯将发区块链游戏 | CSDN极客头条
  14. 课后作业1:字串加密
  15. Grub2引导进入DOS系统
  16. 集体唱好混动技术,传统车企最后的倔强?
  17. bps(bits per second)
  18. 厨神之路三--自制饮品
  19. 音曼Omnos 5.1全景声音响全网首评 声音惊艳
  20. 【C标准库1】math.h

热门文章

  1. python通讯录管理程序的用户可行性_通讯录管理系统项目可行性分析
  2. 用javascript实现以下功能!_模电小实验:用三极管实现触摸开关功能
  3. 为什么数组排序大写字母在前小写字母在后
  4. oracle基础教程实验,Oracle 11g 基础教程与实验指导(配光盘)(清华电脑学堂)
  5. 计算机专硕没有宿舍,没有补贴,不提供宿舍,读研究生还要家里支持,应届生读非全太难...
  6. 解决 pandas 读取数据时内存过大的问题
  7. 一、Git 多人协作模拟实战
  8. SVM支持向量机(上)
  9. 对凸优化(Convex Optimization)的一些浅显理解
  10. 冲击SuperGLUE:基于多任务与对抗训练的Finetune方案解析