热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

数据结构与算法(二)复杂度

吐槽国庆假期第三天,昨天出去胡吃海喝,和朋友出去逛逛寺庙,然后今天早上又来实验室,给猫猫铲臭臭真的臭死我了,一见我就往我身上冲emmmmmmmmmm,今天就把上周就该写的复杂度分析



吐槽

国庆假期第三天,昨天出去胡吃海喝,和朋友出去逛逛寺庙,然后今天早上又来实验室,给猫猫铲臭臭真的臭死我了,一见我就往我身上冲emmmmmmmmmm,今天就把上周就该写的复杂度分析这块写下,因为这块真的还蛮重要的

//我看的是极客时间上一个老师讲的,就是把他讲的梳理一下


本文思维导图

在这里插入图片描述

我觉得复杂度这块主要就是这些,而且分析最多的也是时间复杂度


为什么要有复杂度分析?

这个问题,我之前学的时候重来没想过,写项目的时间重来没想过,好像生活中自己处理事情的时候也没怎么去想自己处理事情的方法所耗费的时间和资源

但是我之前刷ACM题的时候,有几次明明自己写的算法是正确的,但是网站判定的结果就是错误的,要么是时间超了,要么是空间超了,同样的一道题,不同人用的方法不一样,就是结果虽然可能一样,但是别人的算法就是没有超时,或者比自己的所耗费的时间少emmmmmm,这里就是涉及到复杂度的问题了。

但是这块复杂度又如何去算啊?

好像有方法,就是把代码跑一遍,然后看下时间,看下消耗的空间,这样好像也可以唉,但是仔细想下,这个方法很矛盾。

因为我不可能每次写个算法就都重新跑一遍,然后看下时间和空间emmmm这样有点傻,但是意思可以的

这个方法有两个很大的局限性:



  1. 测试结果非常依赖测试环境

    这个很明显啊,我拿个高处理器的电脑去处理同一段代码,和拿个低处理器的处理,肯定高处理器的在其他条件相同的情况下的时候,它处理的时间快啊

  2. 测试结果受数据规模的影响很大

    就好比排序算法一样,数据规模大小很影响排序算法的性能

说了这么多,我们到底需要什么样的分析算法的方式



  • 简单,明了,能在代码运行之前看出来//肯定不是很精确的

  • 不和测试机器环境有关

  • 不受测试规模影响


大O复杂度表示法


大O表示法:称一个函数g(n)是O(f(n)),当且仅当存在常数c>0和n0>=1,对一切n>n0均有|g(n)|<=c|f(n)|成立,也称函数g(n)以f(n)为界或者称g(n)受限于f(n)。记作g(n)=O(f(n))。 定义:如果一个问题的规模是n,解这一问题的某一算法所需要的时间为T(n),它是n的某一函数。T(n)称为这一算法的“时间复杂度”。当输入量n逐渐加大时,时间复杂度的极限情形称为算法的“渐近时间复杂度”。


这个就是百度百科上面的定义,but看这个概念一般人还真的是搞不懂什么意思,反正我当时学的时候也不知道这个是什么鬼意思。但是其实这个概念理解起来也是蛮简单的

因为我们要看代码的执行效率,所以我们要看代码的执行时间和占的空间//占的空间这里简单的小规模算法先不考虑

所以,我们在乎的代码执行的时间,但是我们又如何估算呢?

先看下这个代码

int text(int n){
int sum = 0; //1
int i,n; //2
for (i = 0; i sum += i; //4
}
return sum;
}

我们看下上面这个代码块,一共就执行的就4个重要代码,每段代码块就类似操作,尽管不一样,但是按照现在cpu执行的那么高速的样子,其实每个代码都只执行一点点时间,所以我们认为他们运行的时间都是一样的,记成一Time

现在上面的代码,第1个标记,第2个标记,分别执行了一个Time,然后第3个标记和第4个标记的位置的,是分别执行一个n*Time的时间

所以,总的来说,这段代码运行时间就是(2n+2)*Time,随着n的增大而增大

我们设代码执行的总时间为T(n)

所以,T(n) = (2n+2)*Time 代码执行时间和n成正比

所以,代码执行时间和每行代码的执行的次数成正比

综上所述,大O表示法就出来了

T(n) = O(f(n))

上面公式的个个含义:



  • T(n)表示代码的总的总的执行时间

  • n表示数据规模的大小

  • f(n)表示每行代码的执行次数和

  • 公式中的O表示正比的意思

要注意的点:大O时间复杂度并不是代码的具体执行时间,只是一种趋势,一种变化的趋势

当n特别特别大的时候,可以忽略不记常数项对这个的影响,我们上面代码里面,T(n) = (2n+2)Time 展开时候发现T(n) = 2Time+2nTime,当n为无穷大的时候

其实最后的结果就是:T(n) = O(n)


分析时间复杂度的三个原则


关注法则:只关心执行次数最大的那段代码

因为我们上面也看到了,大O就是一种变化趋势,那些计算的常量什么的其实都不重要,因为当n无穷大的时候,其他的常量,低价,系数什么的其实都没什么作用,所以,我们分析一段代码的时候,只需要看他循环次数最多的地方

int text(int n){
int sum = 0; //1
int i,n; //2
for (i = 0; i sum += i; //4
}
return sum;
}

我们继续看这个例子,这段代码就是只是关心下,执行次数最多的那给循环,其他的地方都无关紧要


加法法则:总的复杂度等于量级最大的那段

先看下下面的代码

int text(int n){
int sum1 = 0;
int sum2 = 0;
int sum3 = 0;
int i,j;
//1
for (i = 0; i <100;i++){
sum1 += i;
}
for(i = 0;i sum2 += i;
}
//3
for (i = 0;i for (j = 0;j sum3 += i;
}
}
return sum1+sum2+sum3;
}

我们再进行分析

第一段代码,就是执行了100次,所以这个就是个常量时间,和n无关

//就是能明显知道执行次数是具体数字的时候,这个常量就不能省略

第二段代码,时间复杂度就是O(n)

第三段代码,时间复杂度就是O(n*n)

然后我们要求这段总的代码的时间复杂度的时候,还是比较下,选最大的那一段,因为还是那句话,把n当成无穷大时候,就可以比较了

所以,这段代码的时间复杂度是O(n*n)


乘法法则:嵌套的复杂度等于里外复杂度的乘积

这个也好理解啊,冒泡就是典型的例子,但是我们还是看下下面的例子

int f(int n){
int sum = 0;
int i;
for(i = 0;i sum += i;
}
return sum;
}
int ff(int n){
int s = 0;
int i;
for(i = 0;i s = s + f(i);
}
return s;
}

这个代码也是很简单,就是一个代码里面调用另一个的函数

所以总的复杂度就是

T(n) = T(n1) * T(n2) = O(n*n)


几种常见的复杂度分析



  • 常量阶

  • 对数阶

  • 线性阶

  • 线性对数阶

  • k方阶

  • 指数阶

  • 阶乘阶

下面举例子说明


O(1) 常数阶

O(1)不是只是执行了一行代码的意思,它只是表示时间复杂度

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

这个整体有3行代码,但是还是O(1)的时间复杂度

只要代码的执行时间不随着n的增大而增大,就是O(1),一般情况下,就是算法中没有循环,递归这些的


O(logn)、O(nlogn)

这块高中数学要学好哇哇哇,对数这块都忘完了

看下下面的代码

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

我们要求这块的时间复杂度就发行很尴尬,不知道要求多少次

一步一步分析,当变量i从1开始取的时候,每次循环都是乘以2,当它大于n的时候,循环结束

然后我们分析下i的变量的取值 2 ,22 ,222 , 22…

也就是2的阶乘

当2的x次方大于n的时候,就循环结束

所以 x = log2 n

所以,这个代码的时间复杂度就是O(log2 n)

然后我们在记对数的时候,通常忽略系数

所以,复杂度统一为O(lngn)

再利用乘法法则,像什么快排的时间复杂度就是O(nlong n)


O(m+n),O(m*n)

这块就是代码里面有两个数据规模,不是一个n了,所以这块要看下


int text(int m ,int n){
int sum1 = 0;
int sum2 = 0;

int i = 1;
for(i = 0; i sum1 += i;
}

for (i = 0; i sum2 += i;
}
return sum1 + sum2;
}

之前我们说的加法法则是看最大的那块,但是我们现在不知道那块最大,m,n都可以无穷大判定下,所以没办法比较,因此,这块的时间复杂度就是O(m+n)

乘法法则类似的套路


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

我们看了时间复杂度这块的概念和大O的表示方法,为什么还有有这四种情况呢,因为传入的数据可能会影响到最后的结果

很明显的例子就是排序算法

先看下一个例子

就是一个简单的从数组中找个数,看它在不在

int find(int []array,int n,int x){
int i = 0;
int pos = -1;
for (i = 0; i if (array[i] == x){
pos = i;
break;
}
}
return pos;
}

这块的分析也就尴尬了,因为我们发现这块程序结束的条件就是找到这个数就结束,或者找不到返回-1,遍历的过程次数不确定

当如果我们要找的数在第一个的时候,找到了,直接break了,那么时间复杂度就是O(1)

如果都找完了还是没找到,这个时候复杂度就是O(n),所以,不同情况下,这段代码的时间复杂度也是不同的

所以,引进了最好、最坏,平均,均摊情况时间复杂度的概念


最好时间复杂度

在最最理想的情况下,执行这段代码的时间复杂度,这块很好理解,比如我算法就是要找元素,第一个就是,所以,执行一次就找到了


最坏时间复杂度

在最最最坏的情况下,执行这段代码的复杂度,还是上面的例子,很简单,就是我找数组还是没找到,这就是最坏的情况


平均时间复杂度

在代码中心所有情况的次数加权平均表示


均摊时间复杂度

在代码执行的所有复杂度情况中绝大部分是低级别的复杂度,个别情况是高级别复杂度且发生具有时序关系时,可以将个别高级别复杂度均摊到低级别复杂度上。基本上均摊结果就等于低级别复杂度。


总结

下次分析时间复杂度的时候,自己也要分析下各种情况



推荐阅读
  • 本文介绍了多种开源数据库及其核心数据结构和算法,包括MySQL的B+树、MVCC和WAL,MongoDB的tokuDB和cola,boltDB的追加仅树和mmap,levelDB的LSM树,以及内存缓存中的一致性哈希。 ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • 专业人士如何做自媒体 ... [详细]
  • 本文总结了《编程珠玑》第12章关于采样问题的算法描述与改进,并提供了详细的编程实践记录。参考了其他博主的总结,链接为:http://blog.csdn.net/neicole/article/details/8518602。 ... [详细]
  • 三角测量计算三维坐标的代码_双目三维重建——层次化重建思考
    双目三维重建——层次化重建思考FesianXu2020.7.22atANTFINANCIALintern前言本文是笔者阅读[1]第10章内容的笔记,本文从宏观的角度阐 ... [详细]
  • 非计算机专业的朋友如何拿下多个Offer
    大家好,我是归辰。秋招结束后,我已顺利入职,并应公子龙的邀请,分享一些秋招面试的心得体会,希望能帮助到学弟学妹们,让他们在未来的面试中更加顺利。 ... [详细]
  • PHP实现汉诺塔算法
    昨天研究了一天汉诺塔算法都没搞懂,感觉自己智商被碾压了,还不如《猩球崛起》中的那一只猩猩!!!起源传说最早发明这个问题的人是法国数学家『爱德华·卢卡斯』。在世界中心贝拿勒斯(在印度 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 本文介绍了如何通过路由汇总和无类域间路由(CIDR)技术来优化路由表,减少路由条目数量,提高网络效率。具体案例展示了路由汇总的实现方法及其对网络性能的影响。 ... [详细]
  • 双指针法在链表问题中应用广泛,能够高效解决多种经典问题,如合并两个有序链表、合并多个有序链表、查找倒数第k个节点等。本文将详细介绍这些应用场景及其解决方案。 ... [详细]
  • 本文介绍了如何使用Visual Studio Code、Sublime Text等编辑器批量删除MATLAB代码中的注释和空行,同时提供了一些高级技巧以确保代码的整洁。 ... [详细]
  • 本文介绍了几种常用的图像相似度对比方法,包括直方图方法、图像模板匹配、PSNR峰值信噪比、SSIM结构相似性和感知哈希算法。每种方法都有其优缺点,适用于不同的应用场景。 ... [详细]
  • LintCode 1218. 计算补数的 JavaScript 算法
    本题要求给定一个正整数,计算其补数。补数是指将该数字的二进制表示逐位取反,然后转换回十进制得到的新数。 ... [详细]
  • 根据经济日报的报道,截至3月15日,包括抖音、今日头条、微信、淘宝、百度、大众点评、微博和小红书在内的多个主流App已经上线了算法关闭功能,用户可以在后台一键关闭“个性化推荐”。 ... [详细]
  • MATLAB实现Sobel边缘检测算法
    图像边缘是指图像中灰度值发生显著变化的区域。Sobel算子是一种常用的边缘检测方法,通过计算图像灰度值的梯度来检测边缘。本文介绍了Sobel算子的基本原理,并提供了基于MATLAB的实现代码。 ... [详细]
author-avatar
快乐生活HAPPY-GO
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有