如何去评估一个算法的时间复杂度?

简介: 要写出一个好的算法,那肯定要学会怎么计算算法的时间复杂度。

1、两种算法的比较

你知道数学家高斯那个关于1+2+3+...+100的故事吗?

高斯7岁那年开始上学。10岁的时候,一次一位老师想治一治班上的淘气学生,他出了一道数学题,让学生从1+2+3……一直加到100为止。他想这道题足够这帮学生算半天的,他也可能得到半天悠闲。谁知,出乎他的意料,刚刚过了一会儿。小高斯就举起手来,说他算完了。老师一看答案,5050,完全正确,老师惊诧不已。问小高斯是怎么算出来的,高斯说,他不是从开始加到末尾,而是先把1和100相加,得到101,再把2和99相加,也得101,最后50和51相加,也得101,这样一共有50个101,结果当然就是5050了,聪明的高斯受到了老师的表扬。

你第一次写1加到100的算法是怎么写的?让我猜猜?

int sum=0;
for(int i=1;i<=100;i++){
    sum = sum +i;
}
retrun sum;

在计算机飞快的算力下,得出结果:5050。
但对于高斯来说,神童就是神童,他却给出了另一个更完美的答案:

sum=0,n=100;
sum=(i+n)*n/2
retrun sum;

第一种方法,如果用于计算1加到100,那么就要循环100此,如果计算到一亿,就要循环一亿次,而下面这种方法,不管加到多少,都只需要执行一次就够了!

2、算法效率与度量方法

上面两个算法,我们是如何得知算法二比算法一好的呢?
下面介绍两种算法效率的度量方法。

2.1 事后度量法

事后度量法,顾名思义,就是算法运行结束后,通过算法执行的时间,去判断这个算法的效率怎么样?

听起来挺不错的,但是基本上很少有算法能采用事后度量的方法来评估算法。为什么?

  • 需要编制好代码:事后度量法,必须基于运行的代码才能度量,如果度量的结果发现这个算法很糟糕,之前编写的过程基本上就白费了。
  • 依赖运行环境:每次度量的结果,很运行算法的计算机状态有很大的关系,不同配置的计算机,比如神威太湖之光和普通的计算机之间运行同一段程序,运行时间差距会很大,就算是同一台计算机,不同时段,计算机CPU和内存占用情况也不相同,容易造成误差。
  • 测试数据设计困难:测试一个算法好不好,不是只运行一次就可以了,往往需要很大的测试数据去不断的运行,才能看见他们之间的差距,比如不同的排序算法,对10个数排序,运行结果基本上看不到差异,但要是对100w个数排序,有时间差距就出来了,但是准备100w个数据,就很麻烦。

2.2 事前度量法

事前度量法:在代码编写前,对算法效率进行评估。
厉害吧,代码还没写,就对算法进行评估,怎么做到的呢?
因为对于高级语言编写的程序来说,程序在计算机在运行所消耗的时间取决于以下因素:

  1. 算法采用的策略方法
  2. 编译产生的代码质量
  3. 问题的输入规模
  4. 机器执行指令的速度

第二条由编译软件来支持,第4条由计算机硬件决定。

所以,除开软硬件的干扰,算法的质量应该取决于:算法的好坏的问题输入的规模。
再看看上面的两种算法

int sum=0;   //执行一次
for(int i=1;i<=100;i++){
    sum = sum +i;  //执行n次
}
retrun sum; //执行1次

第一种算法,一共执行n+2次
那第二种呢?1+1+1=3次

sum=0,n=100;  //一次
sum=(i+n)*n/2  //一次
retrun sum; //一次

我们忽略第一行和最后一行相同的代码,这两个算法的执行效率就是1次于n次的差距。高下立见。

3、函数的渐进式增长

如果我们有4个算法,他们的输入都是n,执行次数分别为,2n,2n+3,3n,3n+1,那个算法效率更高?

n 2n 2n+3 3n 3n+1
1 2 5 3 4
2 4 7 6 7
3 6 9 9 10
10 20 23 30 31
100 200 203 300 301
1000 2000 2003 3000 30001

发现了什么?在n比较小的时候,4个算法的执行次数其实是差不多的,甚至在n=1的时候,3n和3n+1还比2n+1效率高一些,但随着n的增大,函数2n和2n+3的效率明显好于3n+1。
于是我们得出结论:算法2n和算法2n+3执行效率上好过算法3n和3n+1

在仔细看2n和2n+3,会发现,随着执行次数越大,后面的常数3对整体的执行效率的影响越小,所以我们在得出一个结论:
2n和2n+3算法执行效率相同
再来看第二个例子:
一个算法的执行次数是4n+8,一个算法的执行次数是2n^2^+1,他们之间的执行次数是多少?

n 4n+8 2n^2^+1
1 12 3
2 16 9
3 20 19
10 48 201
100 408 20001
1000 4008 2000001

随着n的不断变大,两个算法的执行次数差距也越来越大,在仔细观察发现,造成这种差距的原因,都来自于n的平法,而常数2和4对整体的影响远远小于n平方,于是我们再次得出结论:算法中,与最高次项相乘的函数不重要
这又说明了,算法2n和算法3n执行效率可以看作相同的,统一看作n。
最后看一个例子:
一个算法执行次数是2n^2^+3n+1,一个是2n^3^+3n+1,他们的执行次数是

n 2n^2^+3n+1 2n^3^+3n+1
1 6 6
2 15 23
3 28 64
10 231 2031
100 2031 2000301

随着n值的越来越大,后面的3n+1已经对执行次数的影响基本上可以忽略了,所以得出结论:比较两个算法,只需要比较最高次项就可以了
我们把最后简化的最高次项,记作函数的时间复杂度O。
执行次数2n+1,记作f复杂度O(n).
执行次数2n^2^+n+3,记作时间复杂度O(n^2^),
而那种没有n的算法,比如第二种计算1加到100的算法,只需执行三次,这种算法的时间复杂度,统一记作O(1)

4、常见的时间复杂度

线性阶

下面的代码,他的时间复杂度为n,因为循环体内要执行n次逻辑代码,这种时间复杂度被称为线性阶。

for(int i=0;i<n;i++){
//执行逻辑代码        
}

对数阶

看下面的代码,每次count*2后,都会距离n更近,假设执行x后
2^x^=n,那执行次数x=log~2~n,他的时间复杂度就是O(log~2~n)

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

平方阶

这种循环嵌套的,执行次数为n^2^,时间复杂度为n^2^

for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
     //逻辑
    }
}

5、最坏情况和最好情况

有时候,我们要在n个数字的随机数组里查找某个数,我们按顺序查,可能第一个数字就是要找的值,时间复杂度O(1),也可能是最后一个,时间复杂度O(n),我们把第一种情况乘坐最好时间复杂度,而第二种情况称作最坏时间复杂度。而我们评估一个算法时,往往考虑的是最坏1情况,所以,一般在没有做特殊说明的情况下,时间复杂度,都是说的最坏时间复杂度。

相关文章
|
24天前
|
机器学习/深度学习 算法 程序员
读《趣学算法》:重开算法之门,时间复杂度与空间复杂度
本文是作者阅读《趣学算法》后的笔记,介绍了算法复杂度的基本概念,包括时间复杂度和空间复杂度的不同阶表示,并通过具体例子展示了如何计算和理解算法的效率。
55 2
读《趣学算法》:重开算法之门,时间复杂度与空间复杂度
|
2月前
|
机器学习/深度学习 存储 算法
颠覆认知!Python算法设计中的时间复杂度与空间复杂度,你真的理解对了吗?
【7月更文挑战第22天】在Python算法设计中,时间与空间复杂度是评估算法效能的核心。时间复杂度不仅限于大O表示法,还涵盖平均与最坏情况分析。空间复杂度虽关注额外存储,但也反映内存效率。平衡二者需视场景而定,如利用原地算法减少内存消耗,或牺牲空间加速执行。算法优化技巧,如分治与动态规划,助你在资源与速度间找寻最优解,从而高效应对大数据挑战。
36 3
|
1月前
|
机器学习/深度学习 存储 算法
算法时间复杂度分析
这篇文章讲解了如何分析算法的时间复杂度,包括关注循环执行次数最多的代码段、总复杂度的确定、嵌套代码复杂度的计算方法,并提供了大O阶的推导步骤和常见时间复杂度的列表,同时还介绍了空间复杂度的概念及其重要性。
|
1月前
|
搜索推荐
九大排序算法时间复杂度、空间复杂度、稳定性
九大排序算法的时间复杂度、空间复杂度和稳定性,提供了对各种排序方法效率和特性的比较分析。
59 1
|
2月前
|
存储 算法 搜索推荐
深度剖析 Python 算法:时间复杂度与空间复杂度的爱恨情仇,你站哪边?
【7月更文挑战第23天】在Python算法设计中,时间复杂度与空间复杂度如影随形,反映算法效率与资源消耗。时间复杂度揭示算法随输入规模增长的计算趋势,空间复杂度关注额外存储需求。找最大值示例中,两种实现均具O(n)时间与O(1)空间复杂度,但在排序等复杂场景下,如冒泡排序与快速排序,或哈希表与二叉树查找,权衡变得关键。实时系统偏好低时间复杂度算法,存储受限环境则需关注空间效率。最佳选择依应用场景而定,掌握二者平衡,方能编写高效代码。
28 10
|
2月前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
【7月更文挑战第23天】在Python编程中,掌握算法复杂度—时间与空间消耗,是提升程序效能的关键。算法如冒泡排序($O(n^2)$时间/$O(1)$空间),或使用Python内置函数找最大值($O(n)$时间),需精确诊断与优化。数据结构如哈希表可将查找从$O(n)$降至$O(1)$。运用`timeit`模块评估性能,深入理解数据结构和算法,使Python代码更高效。持续实践与学习,精通复杂度管理。
51 9
|
2月前
|
算法 Python
震惊!Python 算法设计背后,时间复杂度与空间复杂度的惊天秘密大起底!
【7月更文挑战第23天】在Python算法设计中,时间与空间复杂度是幕后操控程序效率的双雄。时间复杂度反映算法执行时间随输入规模增长的速度,空间复杂度则计量算法运行时额外内存的使用。如顺序查找的时间复杂度O(n)与固定空间O(1),对比冒泡排序的O(n^2)时间和快速排序的O(n log n)时间优势,后者虽递归消耗空间,但在多数情况下提供更佳性能。根据需求,可权衡选择,如利用哈希表在充足内存下实现O(1)查找,或在空间受限时,偏好空间效率更高的算法,实现Python代码的高性能与优雅。
40 6
|
1月前
|
机器学习/深度学习 算法 搜索推荐
支付宝商业化广告算法问题之在DNN模型中,特征的重要性如何评估
支付宝商业化广告算法问题之在DNN模型中,特征的重要性如何评估
|
2月前
|
存储 算法 搜索推荐
揭秘!Python算法设计的隐形杀手:忽视时间复杂度与空间复杂度的后果有多严重?
【7月更文挑战第24天】在 Python 编程中, 算法设计是性能与效率的基石。忽视时间复杂度 (如使用 O(2^n) 的斐波那契数列递归算法而非 O(n) 的动态规划版本) 和空间复杂度 (如在插入排序中每次迭代都复制整个已排序数组, 导致 O(n^2) 的空间复杂度) 可能严重拖累程序。性能优化至关重要, 合理的算法设计保证程序高效稳定, 是攀登技术高峰的坚实阶梯。
37 3
|
2月前
|
算法 搜索推荐 数据处理
震惊!Python算法设计背后,时间复杂度与空间复杂度的惊天秘密大起底!
【7月更文挑战第24天】在编程世界里, Python以简洁强大备受欢迎, 但算法设计与复杂度分析对程序性能至关重要。算法是程序的灵魂, 其效率直接影响数据处理能力。时间复杂度衡量算法执行速度, 如冒泡排序O(n²)与快速排序O(n log n)的显著差异; 空间复杂度关注内存占用, 递归算法需警惕栈溢出风险。优秀算法需平衡时间和空间效率, 深入理解问题本质, 迭代优化实现高效可靠。
32 2