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

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

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情况,所以,一般在没有做特殊说明的情况下,时间复杂度,都是说的最坏时间复杂度。

相关文章
|
2月前
|
机器学习/深度学习 缓存 算法
Python算法设计中的时间复杂度与空间复杂度,你真的理解对了吗?
【10月更文挑战第4天】在Python编程中,算法的设计与优化至关重要,尤其在数据处理、科学计算及机器学习领域。本文探讨了评估算法性能的核心指标——时间复杂度和空间复杂度。通过详细解释两者的概念,并提供快速排序和字符串反转的示例代码,帮助读者深入理解这些概念。同时,文章还讨论了如何在实际应用中平衡时间和空间复杂度,以实现最优性能。
82 6
|
4月前
|
机器学习/深度学习 算法 程序员
读《趣学算法》:重开算法之门,时间复杂度与空间复杂度
本文是作者阅读《趣学算法》后的笔记,介绍了算法复杂度的基本概念,包括时间复杂度和空间复杂度的不同阶表示,并通过具体例子展示了如何计算和理解算法的效率。
71 2
读《趣学算法》:重开算法之门,时间复杂度与空间复杂度
|
2月前
|
搜索推荐 算法
插入排序算法的平均时间复杂度解析
【10月更文挑战第12天】 插入排序是一种简单直观的排序算法,通过不断将未排序元素插入到已排序部分的合适位置来完成排序。其平均时间复杂度为$O(n^2)$,适用于小规模或部分有序的数据。尽管效率不高,但在特定场景下仍具优势。
|
2月前
|
机器学习/深度学习 存储 缓存
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
文章主要介绍了排序算法的分类、时间复杂度的概念和计算方法,以及常见的时间复杂度级别,并简单提及了空间复杂度。
45 1
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
|
2月前
|
存储 算法
算法的时间复杂度和空间复杂度
本文详细讨论了算法的时间复杂度和空间复杂度,包括它们的概念、计算方法和常见复杂度的对比,并通过多个实例解释了如何计算算法的时间和空间复杂度。
177 0
算法的时间复杂度和空间复杂度
|
3月前
|
算法 Python
震惊!Python 算法设计背后,时间复杂度与空间复杂度的惊天秘密大起底!
在 Python 算法设计中,理解并巧妙运用时间复杂度和空间复杂度的知识,是实现高效、优雅代码的必经之路。通过不断地实践和优化,我们能够在这两个因素之间找到最佳的平衡点,创造出性能卓越的程序。
45 4
|
3月前
|
算法 搜索推荐 开发者
别再让复杂度拖你后腿!Python 算法设计与分析实战,教你如何精准评估与优化!
在 Python 编程中,算法的性能至关重要。本文将带您深入了解算法复杂度的概念,包括时间复杂度和空间复杂度。通过具体的例子,如冒泡排序算法 (`O(n^2)` 时间复杂度,`O(1)` 空间复杂度),我们将展示如何评估算法的性能。同时,我们还会介绍如何优化算法,例如使用 Python 的内置函数 `max` 来提高查找最大值的效率,或利用哈希表将查找时间从 `O(n)` 降至 `O(1)`。此外,还将介绍使用 `timeit` 模块等工具来评估算法性能的方法。通过不断实践,您将能更高效地优化 Python 程序。
70 4
|
2月前
|
算法 C语言
深入理解算法效率:时间复杂度与空间复杂度
深入理解算法效率:时间复杂度与空间复杂度
|
4月前
|
机器学习/深度学习 存储 算法
算法时间复杂度分析
这篇文章讲解了如何分析算法的时间复杂度,包括关注循环执行次数最多的代码段、总复杂度的确定、嵌套代码复杂度的计算方法,并提供了大O阶的推导步骤和常见时间复杂度的列表,同时还介绍了空间复杂度的概念及其重要性。
|
4月前
|
搜索推荐
九大排序算法时间复杂度、空间复杂度、稳定性
九大排序算法的时间复杂度、空间复杂度和稳定性,提供了对各种排序方法效率和特性的比较分析。
200 1