巩固 | 最全面的算法复杂度分析

巩固 | 最全面的算法复杂度分析

前言算法

这是 2019 年 1 月 20 日的一篇文章,之因此今天从新发一遍,由于我以为算法的复杂度分析是入门算法的一个基本功。有句话说的好,“练武不练功,到老一场空”。我也是正好温习了一遍,若是不常常用,我也有遗忘的时候。数组

另一点就是,以往看似很少的一篇动画技术文章,它的写做和制做很是耗时间的,这个时间会超出你的想象。我我的初心是不想匆匆撩草的完成一篇文章,而后发到公众号,这对我和你来讲是不负责任的。数据结构

因此我仍是选择留出多一点时间好好去写,而后把图设计的更易懂些,不求一天一更,只求每篇文章拿出我最好的状态来分享。ide

巩固 | 最全面的算法复杂度分析
巩固 | 最全面的算法复杂度分析
巩固 | 最全面的算法复杂度分析
巩固 | 最全面的算法复杂度分析
一、数据结构是用来干吗的?性能

数据结构与算法的诞生是让计算机「执行的更快」、「更省空间」的。动画

二、用什么来评判数据结构与算法的好坏?设计

从「执行时间」和「占用空间」两个方面来评判数据结构与算法的好坏。3d


三、什么是复杂度?
code

用「时间复杂度」和「空间复杂度」来描述性能问题,二者统称为复杂度。对象


四、复杂度描述了什么?

复杂度描述的是算法执行时间(或占用空间)与数据规模的增加关系。
巩固 | 最全面的算法复杂度分析

一、和性能分析相比有什么优势?

辅助度分析有不依赖执行环境、成本低、效率高、易操做、指导性强的特色。

二、为何要复杂度分析?

复杂度描述的是算法执行时间(或占用空间)与数据规模的增加关系。
巩固 | 最全面的算法复杂度分析

一、什么方法能够进行复杂度分析?

方法:「大 O 表示法」

二、什么是大 O 表示法?

算法的「执行时间」与每行代码的「执行次数」成正比【T(n) = O(f(n)) 】=》其中T(n)表示算法执行总时间,f(n)表示每行代码执行总次数,而n每每表示数据的规模。

三、大 O 表示法的特色?

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

四、复杂度分析法则

  • [单段代码看频率]:看代码片断中「循环代码」的时间复杂度。

  • [多段代码看最大]:若是多个 for 循环,看「嵌套循环最多」的那段代码的时间复杂度。

  • [嵌套代码求乘积]:循环、递归代码,将内外嵌套代码求乘积去时间复杂度。

------------------❤------------------

时间复杂度

一、什么是复杂度?

全部代码的「执行时间 T(n)」 与每行代码的「执行次数n」 成正比【T(n) = O(f(n)) 】。

二、分析的三个方法

■ 最多法则

忽略掉公式中的常量、低阶、系数,取最大循环次数就能够了,也就是循环次数最多的那行代码。

Example

1// 求n个数字之和
2int xiaolu(int n) {
3   int sum = 0;
4   for (int i = 1; i <= n; ++i) {
5     sum = sum + i;
6   }
7   return sum;
8 }

分析


第二行是一行代码,也就是常量级别,与 n 没有关系,能够忽略,4、五行代码是咱们重点分析对象,与 n 有关,时间复杂度就是反映执行时间和 n 数据规模的关系。求 n 个数据之和须要执行 n 次。因此时间复杂度为 O(n)。

■ 加法法则

总复杂度等于循环次数最多的那段复杂度。

Example

1int xiaolu(int n) {
 2   int sum = 0;
 3   //循环一
 4   for (int i = 1; i <= 100; j++) {
 5     sum = sum + i;
 6   }
 7   //循环二
 8   for (int j = 1; j <= n; j++) {
 9      sum = sum + i;
10   }
11 }

分析


上边有两个循环,一个循环 100 次,另外一个循环 n 次,咱们选择循环次数最多的那一个且和「数据规模 n 」相关的循环。由上可知,咱们很容易选出循环二,即和数据规模 n 有关,循环次数最多,循环次数最多的那段代码时间复杂度就表明整体的时间复杂度,为 O(n) ;

■ 乘法法则

当咱们遇到嵌套的 for 循环的时候,怎么计算时间复杂度呢?那就是内外循环的乘积。

Example

1 for (int j = 1; j <= n; j++) {
2     for(int i = 1; i <= n; i++)
3     sum = sum + i;
4 }

分析


外循环一次,内就循环 n 次,那么外循环 n 次,内就循环 n*n 次。因此时间复杂为 O(n²)。


空间复杂度


一、什么是空间复杂度?

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

Example

1int xiaolu(int n) {
 2   int sum = 0;
 3   //循环一
 4   for (int i = 1; i <= 100; j++) {
 5     sum = sum + i;
 6   }
 7   //循环二
 8   for (int j = 1; j <= n; j++) {
 9      sum = sum + i;
10   }
11 }

分析


在全部代码中,咱们很容易寻找到存储空间相关的代码,就是第二行,申请了一个 常量级别 大小的存储空间,因此空间复杂度为 O(1)。

二、最多见的空间复杂度

O(1)、O(n)、O(n²)。

■ O(1)

常量级的时间复杂度表示方法,不管是一行代码,仍是多行,只要是常量级的就用 O(1) 表示。

Example

1int i = 1;
2int j = 2;
3int sum = i + j;

分析


由于这三行代码,也就是常量级别的代码不随 n 数据规模的改变而改变。(循环、递归除外)

■ O(logn) | O(nlogn)

「对数阶时间复杂度」,最难分析的一种时间复杂度。

Example

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

分析


要求这段代码的时间复杂度就求这段代码执行了多少次,看下图具体分析。

巩固 | 最全面的算法复杂度分析

补充


不论是以 2 为底、以 3 为底,仍是以 10 为底,能够把全部对数阶的时间复杂度都记为 O(logn),由于对数之间能够转换的,参照高中课本。

*■ O(m+n) | O(mn)**

参照上边讲到的加法和乘法法则。

巩固 | 最全面的算法复杂度分析
巩固 | 最全面的算法复杂度分析
一、最好、最坏时间复杂度

所谓的最好、最坏时间复杂度分别对应代码最好的状况和最坏的状况下的执行。

Example

1 //在一个 array 数组中查找一个数据 a 是否存在
2for (int i = 1; i < n; i++) {
3    if (array[i] == a) {
4       return i;
5    }
6 }

分析:


一、最好状况就是数组的第一个就是咱们要查找的数据,上边代码之执行一遍就能够,这种状况下的时间复杂度为最好时间复杂度,为 O(1)。

二、最坏的状况就是数组的最后一个才是咱们要查找的数据,须要循环遍历 n 遍数组,也就对应最坏的时间复杂度为 O(n) 。

二、平均时间复杂度

平均时间复杂度须要借助几率论的知识去分析,也就是咱们几率论中所说的加权平均值,也叫作指望值。

分析


好比上方的例子,假设咱们查找的数据在数组中的几率为 1/2;出如今数组中的几率为 n/1,根据下边的公式就能够算出出现的几率为 1/2n 。

巩固 | 最全面的算法复杂度分析

而后咱们再把每种状况考虑进去,就能够计算出平均时间复杂度。

巩固 | 最全面的算法复杂度分析

三、均摊时间复杂度

■什么是均摊时间复杂度?

好比咱们每 n 次插入数据的时间复杂度为 O(1),就会有一次插入数据的时间复杂度为 O(n),咱们将这一次的时间复杂度平均到 n 次插入数据上,时间复杂度仍是 O(1)。

■ 摊还分析

好比咱们每 n 次插入数据的时间复杂度为 O(1),就会有一次插入数据的时间复杂度为 O(n),咱们将这一次的时间复杂度平均到 n 次插入数据上,时间复杂度仍是 O(1)。

■ 适用场景

通常应用于某一数据结构,连续操做时间复杂度比较低,可是个别状况时间复杂度特别高,咱们将特别高的这一次进行均摊到较低的操做上。

■ 几种复杂度性能对比

巩固 | 最全面的算法复杂度分析

相关文章
相关标签/搜索