4

扎实打牢数据结构算法根基,从此不怕算法面试系列之007 week01 02-07 简单的复杂度分...

 1 year ago
source link: https://www.cnblogs.com/xlfcjx/p/17331751.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1、复杂度分析

复杂度分析本身是非常理论化的一个内容,在计算机科学中,有一个专门的学科叫做——计算复杂性理论

很多童鞋看过《算法导论》,这本书的内容很多很强调算法导论。

但是实际上,对于普通程序员来说,不需要过度强调理论化的内容。因为工作中更多面对的是实际的
软件工程,工程化的工作不需要面对太多理论性的东东。

2、复杂度分析

复杂度分析的作用:是为了表示算法的性能。

对于同样一个任务,可能有多个实现方式,即多个算法。这些不同的算法,它们的时间性能是否有差异呢?


我们虽然可以用一个测试用例,或者一组测试用例实际比较性能差异。
但是,这样的比较结果有局限性。


比如,需要保证运行不同算法的计算机硬件设备的性能一致,甚至深入的说,他们的OS当时的状态都需要是一致的。
这本身很难保证,而且测试结果也与我们的测试用例设计和用例输入相关。


而且,最重要的是这样比较是事后的。

如何突破局限性,如何事前比较呢?
种种这样的需求,都需要我们有一套工具,从数学的层面,用抽象的方式,判断一个算法的性能是怎样的?

为了回应这样的需求,就产生了复杂度分析这样一个概念。

3、复杂度分析和算法性能的关系

复杂度分析,如何表示算法的性能呢?

需要注意的是,算法复杂度分析通常考虑最坏的情况。


这样的思想非常普遍,比如上班时,为了不迟到,考虑最长需要多少时间,甚至将堵车的时间都考虑进去。

即,复杂度分析,表示的是算法运行的上界。


mark

对于我们的线性查找法代码,我们来进行一个复杂度分析吧,代码再一次贴出来:



public static <E> int search(E [] data,E target){ for (int i = 0; i < data.length; i++) if (data[i].equals(target)) return i; return -1; }

mark

具体的分析过程如下:
n = data.length
T 表示时间
T和n的关系到底是怎样的?
T = n?n个元素全部扫描了一遍? 就是n?
T = 2n?if里有比较、有返回结果这2步 就是2n?
T = 3n? 其实if中的data[i],要在数组data中找到i这个元素,是一步寻址,也需要算作一个子步骤。 3n了?
T = 4n?for循环中也包含每次要做的事情,i<data.length,也是一个判断操作,所以4n?

T = 5n?for循环中还有一个i++的操作,所以5n?
T = 5n+2? int i =0;加1次,return -1;加1次,所T=5n+2?
……


其实,再继续分析下去还可以分析出很多可能,就不继续分析了,为什么不继续了呢?


因为真的分析的话,拿出for循环对应的汇编代码,看看这个循环执行了多少指令?


可是拿出汇编代码也不够,因为汇编代码对应着机器指令,而机器指令不仅仅是代码有多少行而已,
还要追溯到运行代码的CPU架构上,有些复杂指令在有些CPU上,就一个指令,但在另外一些CPU上,可能就是多个指令。


对于上层应用软件开发者来说,分析清楚每一行高级语言代码对应着多少机器指令,是一件非常困难,甚至说不可能的事情,其实也没有必要。

而且即便T=5n+2,那这个等式的时间单位是多少呢?是毫秒ms嘛?肯定不对应时间,对应的是指令数,但是一条指令在cpu中执行多久我们知道嘛?

我们不知道。


所以,这些其实我们都不需要考虑,我们需要进行一个化简。这也是计算机科学家们定义复杂度分析这个概念时做过的事儿,没错,他们做了化简。


我们不需要知道执行这样一个循环,对这n个元素操作,每一次循环需要执行多少个指令;
我们只需要知道,整个算法和这个data数组的大小,和这个数据规模n成一个正比的关系即可。


4、O(n)

这个就记作O(n),表示的就是运行时间和数据规模n之间的一个正比关系。
进一步看,如果:
T = c1*n + c2
这个算法我们就可以记作O(n),即常数c1、c2都被我们忽略掉了,即算法复杂度的世界中,常数不重要。

5、复杂度描述的是什么?

复杂度描述的是:随着数据规模的增大,算法性能的变化趋势。

mark

假设有2个算法,分别是T1和T2,它们的详细情况如下:

T1 = 10000n
T2 = 2n²
第一个算法 O(n)级别的算法,第二个算法O(n²)级别的算法。
从复杂度理论的角度来看,第一个算法优于第二个算法。

**因为总是会存在某一临界点n0,当n>n0,T1<T2。
可以计算出,这里的临界点n0为5000。
一旦数据规模大于5000,算法一的性能优势就体现出来了,而且n越大,体现的越明显。

所以O(n)描述的就是随着n的变化,算法的性能的变化趋势,

而不是说n取某个值时,算法的性能。


实际上,如果测试数据小于5000,比如为100时,第二个算法O(n²)反而优于第一个算法O(n);


但是评价算法性能,我们要看n逐渐上涨的情况,甚至看n无穷大的情况

__EOF__

本文作者:皿哥的技术人生
本文链接:https://www.cnblogs.com/xlfcjx/p/17331751.html
关于博主:码农(Android系统定制开发到嵌入式开发均有涉猎、目前从0基础开始系统深入总结嵌入式开发相关技术栈);欢迎各位同行私信交流(本人微信:MosesMin8993),大家一起:学技术、判趋势、拼当下、创未来;交朋友、通爱好、话人生、谈信仰!
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK