一个算法的复杂度可以说也就是一个算法的效率,一般来说分为时间复杂度和空间复杂度。。。

  注意接下来说的均是比较YY的,适用与ACM等不需严格分析只需要大致范围的地方,至于严格的算法复杂度分析的那些数学证明,主定理什么的在《算法导论》这本书上有十分详细的讲解,网上应该也会有人写过,这里就不多说了(其实,是我不会而已o(╯□╰)o。。。)。

  — 到底啥是复杂度呢?先来个栗子。


   小明有10个苹果,有一天他饿了,然后准备吃掉一个苹果,但是小明有中二病,他要吃里面重量最大的那个,于是。。。他需要一个找到那个最大的,可是这应该怎么找呢?

   小明要先量一下第一个苹果多重,然后第二个多重,然后量第三个。。。一直到第十个,量的时候记录当前最重的那个,然后当找完了这十个就好了。。。

   下面来看看这个神奇的找苹果算法的复杂度,有10个苹果,所以需要测量10次才能找到,如果有100个苹果,显然需要测量100次,1000个呢,1000次,n个也就需要n次。

   下面设n为问题的规模,f(n)为运算次数,那么对于小明这个问题来说 f(n)=kn,k是一个常数,这个例子 k=1。(看到如此眼熟的高中数学气息有没有啥感觉。。。)


  — 不用多说就知道如果需要的运算次数多的话,需要花费的时间也就多,所以这就是时间复杂度了,对于上面那个问题的时间复杂度就是 f(n) 了。

  — 但是。。。对于一个问题的常数 k 是比较难搞定的,可能称一下苹果的重量需要一步操作,也可能两步,也可能好几步。所以对于时间复杂度的分析一般是去找渐进复杂度。简单说就是函数 f(n) 省略了常数和低次项,只留下最高次项。比如函数 6n^3+3n^2+2n+10 变成了 n^3 ,因为当n很大很大的时候,变化趋势就是 n^3 型的,再比如 2^n+n^5 就变成了 2^n,因为指数爆炸嘛。。。

  — 这里还要说说符号 O,o 和 Θ,这三个应该高数课会讲。。。O( f(n) ) 表示函数的上界,也就是一个一直比 f(n) 大的函数,然后 o 就是下界,至于  Θ 的话,叫做中界(我YY的一个名字)?也就是和 f(n) 的增长速度一样。。。不过一般来说之后的分析都是用 O 的,因为这个字母好写。。。饿,其实可以理解为因为O是上界,所以算法遇到再坏的情况也不会超过这个函数。

  — 对于一个算法来说一般常用的渐进复杂度函数有 O( n )  O( n^2 )  O( n^3 )  O(1)  O( 2^n )  O( n!)  O( log n)  O( n*logn )  O( n*2^n ) 差不多这些,注意 log 指以2为底的对数。。。函数图就像下面这样:

  — 然后分别比较看看哪种复杂度更好,显然 O(1)是最好的,因为不管问题的规模有多大,都能一下子得到答案。。。然后看看 O(n),小明的问题就是这个复杂度的,如果问题规模是n,需要运行n次,显然已经不错了,挺快的了。。。但是还有一个更快的,O(log n)的,如果n=1000000 那么才只需要运行 20次不到就能得到答案,但是 O(n)的却需要运行1000000次,你说哪个快。


举个栗子:

  要求输入一个n,然后算 1^2+2^2+3^2+4^2+...+n^2的值。

  那么先说一种做法,直接for循环,代码如下:

#include <iostream>using namespace std;int main()
{int n;int sum=0;cin>>n;for(int i=1;i<=n;++i)sum+=i*i;cout<<sum;return 0;
}

  显然这种算法的复杂度是 O (n) 的,因为运行了 n 次嘛。(注意 n 比较大的时候结果会超过 int 的表示范围,具体看 ACM录 常识与错误那篇文章有说。)

  然后看看第二种做法:推出公式来。1^2+2^2+。。。+n^2 = n*(n+1)*(2n+1)/6

  所以第二种做法就是

#include <iostream>using namespace std;int main()
{int n;cin>>n;cout<<n*(n+1)*(2*n+1)/6<<endl;return 0;
}

  这就是 O ( 1 ) 的复杂度了,那么哪个快就不说了。。。


  — 至于后面的 O( n^2 )  O( n^3 )  O( 2^n ) 啊啥的,也是这样算,上面那些里面复杂度最高,效率最差的应该是 O(n!),如果 n 是10,就需要运行 3628800 次,这效率,不多说了。。。

  — 上面说的是运行的次数,然后说说时间,对于现在的个人计算机来说,速度大约是一秒能运行10000000(7个0)次多,这个可以自己写个程序感受一下,for循环10000000次或者更多看看。。。一般来说如果只有加减法 100000000(8个0)次也很快,但是如果有了除法或者其他东西会慢一点。。。

#include <iostream>using namespace std;int main()
{int x;for(int i=0;i<1000000000;++i)x=123*321;    // 对比 x=123/321;return 0;
}

  — 然后对于一个题目来说一般限制了1秒啊2秒啊啥的,那么如果题目的数据规模是100000,那么如果采用的算法是 O(n^2)的,那么就需要运行 10000000000次,也就需要大约1000秒,显然超时了。。。如果算法是 O(n log n)的,那么大约是 1700000 次还是可以接受的。。。至于 O(n) O(1) O(log n)啥的就更不用说了。。。所以说解一个题目的话要注意数据范围和时间限制。。。

  — 这里顺便说下常数吧,之前都是把常数忽略了然后看的是一个大致的增长函数。但是如果常数很大,比如算法只有一个 for 循环,但是里面有1000次运算,那么虽然他的复杂度是 O(n)的,但是对于100000的规模需要运行100000000次,也就很可能会超时了。。。所以当常数比较大的时候要注意看看。。。

  — 至于空间复杂度的话,也就是用的空间的多少和数据规模n的函数,但是因为这个不是很常用而且和时间复杂度几乎差不多,就不多说了。。。

///

  — 那么怎么算复杂度呢,在一些算法和数学的书上有十分严格的数学方法。。。然而,平时不需要的。。。

  — 其实靠肉眼看看就差不多知道了,看看有几个循环,大致估算一下运行多少次,然后就知道了。。。这些当写代码前想算法的时候其实就已经大致了解了。。。

  — 当然这里对于存在递归的算法,就比较麻烦了,这里建议大家学了一些基本的算法之后再来看,因为这里实在是找不到简单的例子。这里有一个主定理(名字就叫主定理),用来计算递归的函数的复杂度计算。比如说一个算法是把问题分成两个小问题,然后在花费 g(n) 的复杂度来合并两个小问题得到大问题的解。那么函数差不多是 f(n)=2*f(n/2)+g(n) 至于 f(n) 怎么推,就可以用上面的那个主定理(这里可以去网上找找这个定理学习一下),其实。。。也可以先猜一下,然后带入那个等式看看行不行。。。

  — 经典的递推比如 f(n)=2f(n/2)+n 的复杂度就是 O(n log n)。。。所以如果 g(n) 如果比 O(n) 要好的话,显然最后的复杂度会比 O(n log n)更好。。。

  — 另外还有一些复杂度分析比如均摊分析就更丧心病狂了,这种分析是找平均值,期望值啥的,通过概率或者是其他什么东西证明运行比如100次的平均复杂度一定不会高于一个数,所以平均就是多少多少的,这个的话就不详细多说了,之后学习比较高级的算法的时候才会接触到。。。(其实是我不会。。。)

  复杂度分析感觉就这些东西,其实大部分算法的复杂度是一眼就能看出来,当然也有一些需要仔细分析这个算法的各种情况才行。。。

转载于:https://www.cnblogs.com/whywhy/p/4865609.html

算法录 之 复杂度分析。相关推荐

  1. 常用排序算法 - 稳定性和复杂度分析

    一.前言 上一篇,只是简单的记录了常用算法的主要思想以及代码实现( 常用算法记录 ); 这次简单的记录一下算法的稳定性以及复杂度 二.稳定性 1. 稳定性的定义 如果两个相等的数据的先后位置,排序前后 ...

  2. 算法 归并排序的复杂度分析(含图解流程和Master公式)

    图解流程 整体流程如下: 细节流程: 第一步: 第二步: 第三步: 第四步: 第五步: 第六步: 第七步: 第八步: 第九步: 第十步: 代码 public static void mergeSort ...

  3. 【排序综合】直接插入排序,希尔排序,快速排序,堆排序,冒泡排序,简单选择排序的简介,实现和算法复杂度分析

    目录 1. 直接插入排序 1.1 直接插入排序简介 1. 什么是直接插入排序 2. 排序思想 1.2 排序实现 1. 排序代码 2. 复杂度分析: 3. 运行结果: 1.3 学习链接 2. 希尔排序( ...

  4. 算法复杂度分析(3600字)

    文章目录 前言 一.复杂度分析的意义 二.复杂度分析基础 1. 大 O O O复杂度表示法 2. 时间复杂度分析方法 2.1 加法法则 2.2 乘法法则 3. 空间复杂度 总结 1. O ( 1 ) ...

  5. python jieba 文本相似度_文本相似度分析(基于jieba和gensim)

    ##基础概念 本文在进行文本相似度分析过程分为以下几个部分进行, 文本分词 语料库制作 算法训练 结果预测 分析过程主要用两个包来实现jieba,gensim jieba:主要实现分词过程 gensi ...

  6. 算法之如何进行算法复杂度分析

    一.什么是复杂度分析? 1.数据结构和算法解决是"如何让计算机更快时间.更省空间的解决问题". 2.因此需从执行时间和占用空间两个维度来评估数据结构和算法的性能. 3.分别用时间复 ...

  7. 怎么算matlab算法复杂度,算法复杂度分析

    1. 何为数据结构?何为算法? 简单来说,数据结构就是数据的存储方式,比如数组就是把数据存在一段连续的内存上,而链表则是通过指针的关联将数据存在任意可用的内存上:栈是先进后出,队列是先进先出. 而算法 ...

  8. 二分检索用途及复杂性_二分查找和三分查找哪个快?算法复杂度与常数无关?复杂度分析的常见误区...

    还记得两三年前,我初看一本算法书,看到二分查找算法的复杂度时,我发现了了不得的东西:二分查找每次查询范围减少一半,需要查询的次数是 ,它的复杂度是 . 我把它改成三分查找,每次查询两个数字与我的目标数 ...

  9. 算法复杂度分析(下)

    前一篇文章算法复杂度分析(上)讲述了复杂度的大 O 表示法和几个分析原则,这篇文章我们来讲讲另外几种复杂度,最好情况时间复杂度(best case time complexity).最坏情况时间复杂度 ...

最新文章

  1. springboot(十六):使用Jenkins部署Spring Boot
  2. Dockerfile镜像优化方案指引
  3. 比特币现金(BCH)是5月的货币之王
  4. umi不输出html文件,部署 - UmiJS 中文文档
  5. python读取txt文件并写入excel-Python实现读取txt文件并转换为excel的方法示例
  6. 潜在狄利克雷分配(Latent Dirichlet Allocation,LDA)
  7. pip不是内部或外部命令,也不是可运行的程序 或批处理文件--解决办法
  8. 一文讲清数据治理、数据管理、数据资产管理区别,数据专家必看
  9. mysql服务器守护程序_MySQL主从服务器的守护进程监视
  10. java 获取物理路径_JSP---jsp页面获取物理路径
  11. jquery select
  12. 敏捷开发中史诗故事与用户故事的颗粒度
  13. 剑桥女博士创立情绪识别 AI 公司,帮助自闭症患者理解他人表情
  14. python用户管理系统模块_Django的用户模块与权限系统的示例代码
  15. Permission denied:通过共享复制,与打包后解压,目录权限不一样
  16. 95%的码农都在用的编程神器,值得一看!
  17. qpython3手机版怎么运行不了_QPython3手机版
  18. python爬取LOL皮肤
  19. esxi时间服务器在哪配置文件,如何使用vSphere Web Client配置 ESXi时间同步?
  20. 最新TIM校园学校表白墙系统源码+UI挺不错

热门文章

  1. C 语言运算符优先级
  2. Jackson 注解 -- 使用构造器
  3. SpringBoot中请求映射的原理(源码)
  4. 数据库操作技术--Spring jdbcTemplate
  5. STM32开发 -- 系统架构
  6. UNIX再学习 -- 发送信号
  7. UNIX再学习 -- 静态库与共享库
  8. Android CookieSyncManager同步cookie
  9. android界面之美---自定义网络请求进度加载对话框
  10. 双流棠湖中学怎么样_棠湖中学教师团队荣获四川省“最美教师团队”!