算法妙应用-算法的复杂度

算法词云.png

0、什么是算法的复杂度?

对于任何一个程序来讲,均可以从三个方面进行分析,分别是 输入处理输出,也即 IPO(Input、Process、Output),这种分析方法对硬件和软件程序都是适用的。算法

数据的来源(Input):能够是硬件传感器收集的,也能够是从网上爬取的...。数据的输出(Output):能够显示在网页上,安卓APP上,电子屏幕上...。而最重要的是程序处理,能够对数据进行简单的处理,也能够对数据进行挖掘...。编程

就拿最简单的 Hello World 程序来讲,也是由这三方面组成的,输出函数(处理)帮你处理输入的 “Hello World” 字符串(输入),而后再帮你将这些字符输出显示到控制台上(输出)。大到如今热门的技术,物联网、大数据,人工智能等,作的也无非都是上面三个方面内的事情,关于这些,读者能够思考一下。bash

评价一个程序的复杂程度,关键也是看程序中处理数据的这部分,对数据处理就要用到算法了。什么?你说你没有用过算法,其实从你编程开始的第一句 “Hello World” 就注定编程和算法分不开了,一个输出函数背后也一样有算法呀,只是你在使用算法的时候并无意识到你在用算法罢了(嘿嘿,就是这么神奇~)。微信

算法是一个程序的灵魂,就比如没有蛋的泡面是没有灵魂的同样。一个好的算法能够有不少的应用,好比在美剧《硅谷》中,主角发明了一种压缩算法,将它用在音乐、云存储、视频等方面都大获成功。虽然故事是虚构的,可是在一方面也说明了算法的重要性。数据结构

分析一个算法的复杂度,也是在分析一个算法的好坏优劣,简单高效的算法才是咱们应该追求的,而复杂低效的算法则是咱们须要改进的。算法的复杂度包括 时间复杂度空间复杂度,下面将用尽可能少的概念来帮你搞懂这两个度。函数

一、什么是算法的时间复杂度?大数据

讨论算法的时间复杂度,也是在讨论程序使用该算法运行的时间。常常听到身边的同窗说个人电脑好慢呀,打开个软件都要一分多钟,急死人了。这从算法的角度看,只能说电脑硬件比较差,不必定说程序写的很垃圾(固然也有可能有程序的锅),一样的程序可能在别人配置高的电脑上打开就很快。因此你看单纯从程序运行须要的时间长短上,并不能反映算法的优劣,由于这和运行的设备也有很大关系(计算机计算主要用到的是 CPU 和 GPU)。人工智能

算法的时间复杂度并不能以具体的时间数值为单位(如1秒钟,1分钟等),那算法复杂度中的时间单位是什么呢?这个时间单位其实更像是程序中执行的次数或者步骤数。spa

举个栗子,当你忘记东西放哪里了,可能会把全部的抽屉都找一遍,假如你有 n 个抽屉,那么找完 n 个抽屉就能够找到你的东西了,每一个抽屉都找了一遍,就找了 n 遍。算法的时间复杂度(运行时间)用大 O 表示(不须要关心大 O 表示法怎么来的,就是个名字),把你找东西的这个过程写成程序,算法的时间复杂度就是 O(n),是否是感受算法其实就在咱们中间。code

在上面这个例子中,最好的状况是,当你找完第一个抽屉,你就找到你的东西了,这固然是最好的了,用大 O 表示法表示就是 O(1),可是这样的状况存在偶然性,并不能表明算法的复杂度;最坏的状况是,直到你找完最后一个抽屉,累的要死,你才找到你的东西,用大 O 表示法表示就是 O(n)。位于最坏和最好之间的状况是,当你找到中间一个抽屉时,你找到的你的东西了,用大 O 表示法表示就是 O(n/2)。

那么这三种状况,哪种应该表明算法的时间复杂度呢?最好的状况毕竟是小几率事件,不具备普适性,确定是不能表明算法真实的时间复杂度。平均的状况,确实在必定程度上能够反映出算法的时间复杂度,可是学过数学的咱们知道,平均值容易受到极端值的影响(在评委打分时也常常是去掉最高分和最低分),因此平均状况也不是很合适。而最坏的状况却能够给咱们一种保证,咱们内心也能够有一个预期,这个算法在最差的状况下表现如何(就像咱们作事也经常考虑最坏的状况同样),因此咱们用最坏状况下的时间复杂度来衡量算法的时间复杂度

对于大 O 括号内的参数(或者称为操做数)的系数,每每被咱们主动忽略,如一个计算出所需次数为 n/2 的算法,用大 O 表示法表示是 O(n),而对于计算次数是个常数(如 1,5, 9)的算法,用大 O 表示法表示都是 O(1),这点是须要咱们注意一下的。为何这样作呢?由于对于计算次数是 n2/2 + n/2 + 5 这样的算法,起决定做用的是 n,而不是 n 前面的系数,当 n 为无穷大时,n 前面系数的影响就微不足道了,最终这个算法的时间复杂度用大 O 表示法为 O(n2 + n)。

二、什么是算法的空间复杂度?

程序运行时确定是要消耗空间资源的,寄存器、内存和磁盘等。输入和输出这两部分占用空间是必需的,因此程序处理的空间指的是程序运行算法时所需的那部分空间。先来看个例子,交换两个数的值,相信你们都作过吧,通常的方法是找一个中间变量存储其中一个数的值,再让一个数等于另外一个数的值,另一个数等于中间变量的值,就像下面的伪代码这样。

// 交换 a 和 b
temp = a
a = b
b = temp
复制代码

栈这种数据结构,我都应该很熟悉,特色是先进后出(FILO),交换的这两个数确定都是要放在栈中的,但因为引入了中间变量实现,因此在程序栈中还要有中间变量的空间,一个变量占用一块栈空间(想象一下),咱们用一个格子来表示,就像下面这样,中间变量也要占用一个格子(其实这个格子在其余栈中叫作 ,如 Java虚拟机的本地方法栈和虚拟机栈,帧又是一种数据结构)。

由于这个值交换算法用到了中间变量,而中间变量又要占用一个格子,因此这个算法的空间复杂度用大 O 表示法表示就是 O(1)。

算法复杂度.png

相比较而言,算法的空间复杂度比较简单,因此咱们在讨论一个算法时,更多的是讨论算法的时间复杂度。

三、一些常见的大 O 运行时间

  • O(1),如 y = x + 1,只须要一次计算即可获得结果。
  • O(logn),也称为对数时间,如二分查找算法。
  • O(n),也称为线性时间,如咱们上面例子中的找东西,用的就是简单查找算法。
  • O(n*logn),如快速排序算法。
  • O(n2),如选择排序算法。
  • O(n!),如著名的旅行商问题。

这里提到的算法,将在后面的文章中讨论,感兴趣的小伙伴不妨先搜索了解一下。

上面几种大 O 运行时间,反应在图中以下(注意:图中曲线并不必定从原点开始画的,只须要知道算法运行时间的大概走势就能够了):

几种常见的算法时间.jpg

算法的速度,指的并非时间,而是增速,反应的在图中就是曲线的斜率,能够看到,随着输入的增长,有的算法所须要的时间越来长,也就是使用这种算法的程序会愈来愈慢。

四、小结

算法的复杂度和须要的时间、空间都有关系,咱们更多谈论的是算法的时间复杂度,算法的时间复杂度不是以秒为单位算法运行的速度是从其增速的角度度量的,也便是输入越多,算法运行的时间改变的快慢。一个好的算法应该是时间复杂度和空间复杂度都比较低,通俗的说就是花最少的时间和精力达到最好的效果,可是这两样每每是很难同时作到的,这就须要咱们牺牲同样来作到尽量的更好。

——本文转自个人微信公众号《编程心路》。

相关文章
相关标签/搜索