数据结构算法入门--一文了解什么是复杂度

640?wx_fmt=jpeg

图片来自 Pixabay,作者:TeroVesalainen

2019 年第 74 篇文章,总第 98 篇文章

本文大约 3000 字,阅读大约需要 10 分钟

最近会开始更新一个数据结构算法的学习系列,同时不定期更新 leetcode 的刷题。

这是第一篇文章,在开始介绍各种数据结构和算法之前,先了解下什么是复杂度,包括时间复杂度和空间复杂度。

今日推荐阅读:

精心挑选了这些牛人的公众号,来看看吧!


什么是复杂度分析

  1. 数据结构和算法解决是“如何让计算机更快时间、更省空间的解决问题”。

  2. 因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能。

  3. 分别用时间复杂度和空间复杂度两个概念来描述性能问题,二者统称为复杂度。

  4. 复杂度描述的是算法执行时间(或占用空间)与数据规模的增长关系

为什么需要复杂度分析

  1. 和性能测试相比,复杂度分析有不依赖执行环境、成本低、效率高、易操作、指导性强的特点。

  2. 掌握复杂度分析,将能编写出性能更优的代码,有利于降低系统开发和维护成本。

如何进行复杂度分析

对于时间复杂度的分析,通常使用大O复杂度表示法,表示代码执行时间随数据规模增长的变化趋势,所以,也叫作渐进时间复杂度(asymptotic time complexity),简称时间复杂度

用公式表示,就是 T(n) = O(f(n))表示,其中 T(n) 表示算法执行总时间,f(n) 表示每行代码执行总次数,而 n 表示数据的规模。

由于时间复杂度描述的是算法执行时间与数据规模的增长变化趋势,所以常量阶、低阶以及系数实际上对这种增长趋势不产决定性影响,所以在做时间复杂度分析时可以忽略这些项。

具体分析的时候,有下列三个方法:

  1. 单段代码只看循环次数最多的部分

  2. 多段代码取复杂度最高的:即有个多个循环,但只看循环次数量级最高的那段代码

  3. 乘法法则--嵌套代码进行乘积:多个循环嵌套,就是相乘

常见的时间复杂度

按照数量级递增,常见的时间复杂度量级有:

  • 常量阶 O(1)

  • 对数阶 O(logn)

  • 线性阶 O(n)

  • 线性对数阶 O(nlogn)

  • 平方阶 O(n^2),立方阶 O(n^3)…k次阶 O(n^k)

  • 指数阶 O(2^n)

  • 阶乘阶 O(n!)

其中,最后两种情况是非常糟糕的情况,当然 O(n^2) 也是一个可以继续进行优化的情况。

接下来简单介绍上述复杂度中的几种比较常见的:

O(1)

O(1) 表示的是常量级时间复杂度,也就是只要代码的执行时间不随 n 的增大而增长,都记作 O(1) 。一般只要算法不包含循环语句和递归语句,时间复杂度都是 O(1)

像下列代码,有 3 行,但时间复杂度依然是O(1),而非 O(3)

a = 3
b = 4
print(a + b)
O(logn)、O(nlogn)

O(logn) 也是一个常见的时间复杂度,下面是一个 O(logn) 的代码例子:

i = 1
count = 0
n = 20
while i <= n:count += 1i *= 2
print('while 循环运行了 {} 次'.format(count))

这段代码其实就是每次循环都让变量 i 乘以 2,直到其大于等于 n,这里我设置 n=20,然后运行了后,输出结果是循环运行了 5 次。

实际上这段代码的结束条件,就是求 2^x=n 中的 x 是等于多少,那么循环次数也就知道了,而求 x 的数值,方法就是 640?wx_fmt=png ,那么时间复杂度就是 640?wx_fmt=png

假如上述代码进行简单的修改,将 i *= 2 修改为 i *= 3 ,那么同理可以得到时间复杂度就是 640?wx_fmt=png

但在这里,无论是以哪个为对数的底,我们都把对数阶的时间复杂度记为 O(logn)

这里主要原因有两个:

  1. 对数可以互换,比如 640?wx_fmt=png,也就是 640?wx_fmt=png,常量640?wx_fmt=png

  2. 基于前面的理论,系数可以被忽略,也就是这里的常量 C 可以忽略

基于这两个原因,对数阶的时间复杂度都忽略了底,统一为 O(logn) 。

至于 O(nlogn) ,根据乘法法则,只需要将对数阶复杂度的代码,运行 n 次,就可以得到这个线性对数阶复杂度了。

注意, O(nlogn) 是非常常见的时间复杂度,常用的排序算法如归并排序、快速排序的时间复杂度都是 O(nlogn)

O(m+n)、O(m*n)

前面介绍的情况都是只有一个数据规模 n ,但这里介绍有两个数据规模的情况--m和 n

# O(m+n)
def cal(n, m):result = 0for i in range(n):result += ifor j in range(m):result += j * 2return result

简单的代码示例如上述所示,如果事先无法评估 m 和 n 的量级大小,那么这里的时间复杂度就没法选择量级最大的,所以其时间复杂度就是 O(m+n) 。

同理,对于嵌套循环,就是 O(m*n) 的时间复杂度了。

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

这四种复杂度的定义如下:

  • 最好情况时间复杂度:代码在最理想的情况下执行的时间复杂度;

  • 最坏情况时间复杂度:代码在最坏情况下执行的时间复杂度;

  • 平均情况时间复杂度:代码在所有情况下执行的次数的加权平均值表示

  • 均摊时间复杂度:代码执行的所有复杂度情况中,绝大多数都是低级别的复杂度,个别情况会发生最高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊复杂度就等于低级别复杂度,也可以看作是特殊的平均时间复杂度。

为什么会有这四种复杂度呢?原因是:

同一段代码在不同情况下时间复杂度会出现量级差异,为了更全面、更准确描述代码的时间复杂度,引入这四种复杂度的概念;

但通常除非代码是出现量级差别的时间复杂度,才需要区分这四种复杂度,大多数情况都不需要区分它们。

下面是给出第一个代码例子:

# 在数组 arr 中查找目标数值 x
def find(arr, x):for val in arr:if val == x:return Truereturn False

这个例子假设数组 arr 的长度是 n ,那么它最好的情况,就是第一个数值就是需要查找的 x ,此时复杂度是 O(1) ,但最坏情况就是最后一个数值或者不存在需要查找的 x ,那么此时就遍历一遍数组,复杂度就是 O(n) ,因此这段代码最好和最坏情况是会出现量级差别的,O(1) 和 O(n) 分别是最好情况复杂度和最坏情况复杂度。

而这段代码的平均情况时间复杂度是 O(n) ,具体分析就是首先考虑所有可能的情况以及对应出现的概率,可能发生的情况先分为两种,存在和不存在需要查找的数值 x,也就是分别是 1/2 的概率,然后对于存在的情况下,又有 n 种情况,即出现在数组任意位置的概率都是均等的,那么它们的概率乘以存在的概率就是 1/2n ,接着再考虑每种情况需要搜索的元素个数,其实就是代码执行的次数,这个分别就是从 1 到 n,并且对于不存在的情况,也是 n ,需要遍历一遍数组才发现不存在,所以平均时间复杂度的计算过程如下:640?wx_fmt=png加权平均值,也叫期望值,所以平均时间复杂度的全称应该叫加权平均时间复杂度或者期望时间复杂度

这里用大 O 表示法表示,并且去掉常量和系数后,就是 O(n)。

最后介绍下均摊时间复杂度,需要满足以下两个条件才使用:

1)代码在绝大多数情况下是低级别复杂度,只有极少数情况是高级别复杂度

2)低级别和高级别复杂度出现具有时序规律均摊结果一般都等于低级别复杂度

空间复杂度分析

和时间复杂度的定义类似,空间复杂度全称就是渐进空间复杂度(asymptotic space complexity),表示算法的存储空间与数据规模之间的增长关系

简单介绍下一个程序所需要的空间主要由以下几个部分构成:

  • 指令空间:是值用来存储经过编译之后的程序指令所需要的空间。

  • 数据空间:是指用来存储所有常量和变量值所需的空间。其主要由两个部分构成:

    • 存储常量和简单变量所需要的空间

    • 存储复合变量所需要的空间。这一类空间包括数据结构所需要的动态分配的空间

  • 环境栈空间:用来保存函数调用返回时恢复运行所需要的信息。例如,如果函数 fun1 调用了函数 fun2,那么至少必须保存 fun2 结束时 fun1 将要继续执行的指令的地址。


本系列主要参考极客时间上的数据结构与算法之美课程,目前这门课正在做活动,拼团只需 65 元,课程的设计非常合理,而且介绍得很详细,有对应的代码辅助理解,还有一个开源的 GitHub,目前已经有1w+的star了:

https://github.com/wangzheng0822/algo

640?wx_fmt=jpeg

欢迎关注我的微信公众号--算法猿的成长,或者扫描下方的二维码,大家一起交流,学习和进步!

640?wx_fmt=png

如果觉得不错,在看、转发就是对小编的一个支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/408487.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java String和Date的转换 Date类型操作

String—>Date String dateString "2012-12-06 "; try {SimpleDateFormat sdf new SimpleDateFormat("yyyy-MM-dd ");Date date sdf.parse(dateString); } catch (ParseException e) {System.out.println(e.getMessage()); } /*** 字符串转换到时间格…

一文了解数组

2019 年第 75 篇文章&#xff0c;总第 99 篇文章”数据结构算法入门系列的第二篇&#xff0c;这次介绍下数组&#xff0c; 数组是一个最基础而且常见的数据结构&#xff0c;几乎每种编程语言都有。上一篇文章&#xff1a;数据结构算法入门--一文了解什么是复杂度今日推荐阅读…

Python3.8 了解的差不多了吧,Python3.9 新特性了解一下!

"Python学习开发"&#xff0c;一个值得加星标的公众号。正文共&#xff1a;4946 字 1 图预计阅读时间&#xff1a;13 分钟作者:陈祥安原文有删改:https://docs.python.org/3.9/whatsnew/3.9.html本文将解释 Python 3.9 中的新特性&#xff0c;而不是 3.8。有关完整的…

React工作(1)---export导出

import React, { Component } from react;class List extends Component {constructor(props) {super(props);}render() {return <div>1111</div>;} }export default List;

首发:适合初学者入门人工智能的路线及资料下载

本文为AI入门提供了一个简易的学习路线&#xff0c;并提供了代码和数据集下载。&#xff08;黄海广&#xff09;一、前言AI以及机器学习入门&#xff0c;初学者遇到的问题非常多&#xff0c;但最大的问题就是&#xff1a;资料太多&#xff01;&#xff01;&#xff01;看不完&a…

动态SQL中变量赋值

在动态SQL语句中进行变量的值绑定比较麻烦&#xff0c;这儿做个记录 declare COUNT int,sql nvarchar(max) set sql select COUNT count(id) from tbl_sys_dict where root_key WT_TYPE execute sp_executesql sql, NCOUNT int output, COUNT output print COUNT 转载于:htt…

数据结构算法入门--链表

2019 年第 76 篇文章&#xff0c;总第 100 篇文章 本文大约 3200 字&#xff0c;阅读大约需要 10 分钟 数据结构算法系列&#xff1a; 数据结构算法入门系列第三篇--链表&#xff0c;链表也是非常常见的数据结构&#xff0c;面试过程中也会经常考到相关的题目。 本文首先介绍链…

react学习(3)----不能在该位置用setstate

this.setState({ pageIndex: 1, pageSize: 10, });

后台命名查询sql查某几个字段传到前台

dwr调用查出数据库字段 传给前台显示 前台只能接受list 后台数据放进list传入前台 name-quary中 <!-- 定义sql 通过单位id 查单位名称 --> <sql-query name"getStationName"> <![CDATA[ select STATION_ID,STATION_NAME from MF_STATION wher…

带你少走弯路:强烈推荐的Keras快速入门资料和翻译(可下载)

上次写了TensorFlow和PyTorch的快速入门资料&#xff0c;受到很多好评&#xff0c;读者强烈建议我再出一个keras的快速入门路线&#xff0c;经过翻译和搜索网上资源&#xff0c;我推荐4份入门资料&#xff0c;希望对大家有所帮助。备注&#xff1a;另外两个入门资料很负责任地说…

hadoop遇到的问题及处理

1:杀掉hadoop作业 列出作业 ./hadoop job -list杀掉 ./hadoop job -kill job_id1&#xff1a;某些节点出现running asprocess XXX. Stop it first 这是由于各节点登录用户为root&#xff0c;在启动hadoop前&#xff0c;务必将各节点用户切换至普通用户hadoop下&#xff0c;切换…

Mac 下安装配置 Python 开发环境

图片来源&#xff1a;Unsplash&#xff0c;作者 Markus Spiske 2019 年第 77 篇文章&#xff0c;总第 101 篇文章前言记录下 Mac 电脑的开发环境安装配置&#xff0c;主要包括&#xff1a;安装&使用Homebrew安装使用 git安装 anaconda&#xff0c;配置 python3 环境安装 ju…

react学习(5)----通过设置初始值控制页面render渲染

boothActivityCode: this.props.location.query.code || ,

【Android源代码下载】收集整理android界面UI效果源码

在Android开发中&#xff0c;Android界面UI效果设计一直都是很多童鞋关注的问题&#xff0c;今天给大家分享下大神收集整理的多个android界面UI效果&#xff0c;都是源码&#xff0c;都是干货&#xff0c;贡献给各位网友&#xff01; 话不多说&#xff0c;直接上效果图&#xf…

一文了解类别型特征的编码方法

来源&#xff1a;Unsplash&#xff0c;作者&#xff1a;an Rizzari2019 年第 78 篇文章&#xff0c;总第 102 篇文章目录&#xff1a;问题描述数据准备标签编码自定义二分类one-hot 编码总结问题描述一般特征可以分为两类特征&#xff0c;连续型和离散型特征&#xff0c;而离散…

UNIX网络编程--读书笔记

会集中这段时间写UNIX网络编程这本书的读书笔记&#xff0c;准备读三本&#xff0c;这一系类的文章会不断更新&#xff0c;一直会持续一个月多&#xff0c;每篇的前半部分是书中讲述的内容&#xff0c;每篇文章的后半部分是自己的心得体会&#xff0c;文章中的红色内容是很重要…

react学习(6)----react样式多用内联

<div style{{ textAlign: center }}><Button type"primary" style{{ marginRight: 10px }}>保存</Button><Button>取消</Button><Button type"primary" style{{ marginLeft: 10px }}>发布</Button></div>…

如何用栈实现浏览器的前进和后退?

2019 年第 79 篇文章&#xff0c;总第 103 篇文章数据结构与算法系列的第四篇文章&#xff0c;前三篇文章&#xff1a;前言浏览器的前进和后退功能怎么用栈来实现呢&#xff1f;这里先介绍一下栈的定义和实现&#xff0c;并介绍它的一些常用的应用&#xff0c;最后再简单实现一…