[算法]算法引论:时间复杂度

/*依旧写在前面:
欢迎讨论,本节内容主要就复习算法的一些数学基础以及程序设计的一些概念
参考文献:数据结构与算法分析(黑皮书)
新编数据结构
参考课程:慕课网玩转算法面试(?是这个名字吗dbq)
最后,部分图片参考网络
*/
本讲主要侧重的问题:
1.算法届主要讨论的问题是什么?
2.时间复杂度是什么?什么是时间频度?大O和f(n)之间的关系?
3.如何去计算一个算法的时间复杂度?
4.关于时间复杂度,业界和学术界的看法分别是什么?
5.关于时间复杂度,实际操作中容易出现的理解错误
6.算法的时间复杂度,实际上是与用例相关的

引言:算法届讨论的问题到底是什么?

我们先来看两个问题,

  • 第一个问题是选择问题,通常我们将有一组N个数而要确定其中第k个最大者的问题称之为选择问题,诚然面对这个问题我们有很多解决办法:

    • 把这些数据读进数组中,然后通过递减的方式一个个排序,然后返回位置k上的元素
      如图所示:
      在这里插入图片描述

    • 或者可以把前k个元素读入数组并(以递减的顺序)对其排序,接着,再把剩下的元素逐个读入。当新元素被读到的时候,如果它小于数组中第k个元素则忽略,否则就将其放在数组中正确的位置上,同时将数组中的第一个元素挤出数组

    • 这两种算法都很简单,也可以解决问题,所以我们自然要问:到底那个算法更好?哪个算法更高效?诚然,如果我们的数据量足够小,那么这些算法的运行时间不到几毫秒,但是如果我们把数据量加到百万千万级别的,那么这些算法处理的时间很可能超过一天。

  • 所以在许多问题中,可以写出一个解决问题的方式并不够,有的时候还需要考虑在巨大数据量上运行的时间问题,而这个,则就是重多工程师们需要搞定并且优化的问题了

什么是大O(时间复杂度)

一,一些关于时间复杂度的基本概念

  • 大O的形式定义:
    在这里插入图片描述

  • 频度T(n):算法的时间复杂度以算法中重复执行的次数(简称为频度)作为算法的时间度量,一般不必精确计算,只需计算大概就好了,如O(1),O(logn),O(N),O(n^2)

  • 因此,我们可以得出f(n),T(n)与大O的关系:
    O(f(N))表示算法所需执行的指令数,并且和f(n)成正比M(这个常数M=T(n)/F(n)),所以O(f(n))是f(n)的一个上届。

  • 这里的概念不用深究,只需要理解就好

这里举个例子:
二分查找法的大O是O(logn)级别的---------------------所以它所需执行的指令数为alogn
寻找数组中的最大/最小值O(n)级别的--------------------------所以它需要执行的指令数为b
n
假设有一个算法的是O(n)级别的,但是它的常数是10000n,算法B是O(n^2)级别的,所需执行指令数为10n ^ 2,在10-1000级别的时候,算法A都是比算法B高效的,然而随着数据量的加大,知道10 ^ 6级别的数据的时候,算法A的执行效率是算法B的0.001倍
同时这样的例子也印证了一个概念,算法的运行效率是和常数M没有关系的,而是和大O中的n的级别有关

二,如何确定时间复杂度

  • 确立算法时间复杂度的方法一般如下:

    • 1.确定问题规模n:通常在形参中给出
    • 2.计算算法的语句频度T(n),通常以算法中的基本运算为核心(循环)求算法执行的次数
    • 3.用大O表示,只保留T(n)的最高阶项,如果这个最高项目的序数不为1,除去这个序数
  • 例题1:分析以下算法的时间复杂度:

void func(int n){
	int i=1,k=100;
	while(i<=n)
	{
		k++;
		i+=2;
	}
}
  • 那么,对于这种问题,我们怎么进行分析呢?
  • 1.从数学定义入手:
    设while循环执行的次数为T(n)次,i从1开始递增,最后取值为1+2T(n),因此有1+2T(n)<=n,因此可推导出T(n)<=(n-1)/2=O(n)
  • 2.从执行多少步入手:
    i=1,到最后i=n,每一次循环i加2,所以执行的步骤也就是为(尾项-首项)/每一次改变的量的大小,所以T(n)=(n-1)/2,也就是i从1到n,执行了n-1/2步,通过执行的步数我们可以判断出这是一个O(n)级别的算法
  • 所以该算法的时间复杂度为O(n),也就是随着数据规模的增加,所用时间与数据规模成线性关系
  • 例题2:让我们再分析一下下面这个算法的时间复杂度
void func(int n){
	int i=1;
	while(i<n)
	{
		i=i*2;
	}
}
  • 同样的,让我们再次分析这个算法的时间复杂度
    • 定义法:
      假设while循环里i执行了T(n)步,那么i=1+T(n)^ 2,因此有1+2^T(n) < n,所以 2 ^ T(n)<n-1(为了简化运算可以近似看为n),所以T(n)=log2(n-1)≈log2N,所以复杂度为O(log2N)
    • 执行步数法:
      i的初始值为1,i为了停止循环最终的运行结果是i=n,每一次循环i*2,那么为了达到n,i需要执行log2(N-1)步,
  • 这种方法各有利弊,大家可以权衡使用

三,不同时间复杂度的算法的执行效率与量级

  • 关于不同时间复杂度的算法,他们执行效率如图所示

在这里插入图片描述四,关于学术界和业界对于算法的一些不同看法:

  • 在学术界,严格的讲,O(f(n))表示算法执行的上界 归并排序的时间复杂度是O(logn),但是也可以说是O(n^2)的
  • 但是在业届,一般值得是算法执行的最低上界

五,一个在算法问题中容易出错的问题

  • 在我们设计算法的时候,经常很容易设计出AlogA+B,或者其他组合的算法,这时候我们往往容易把A和B混淆
  • 例如我们对邻接表实现的图进行遍历,时间复杂度为O(V+E)
  • 这里我们举出一个例子

有一个字符串数组,将数组中的每一个字符按照字母排序,之后再将整个字符串数组按照字典序排序,整个操作的时间复杂度是多少?

错误思路:
O(nlogn+nlogn)= O(n^2logn)
这一步混淆了字符串的长度和数组中有多少数组的参数搞混淆了,这两个不是一个n
正确思路:
假设最长的字符串长度为s,数组中有n个字符串
对每一个字符串按照字母序排序O(slogs)
将数组中的每一个元素按照字母序排序:O(n
slog(s))
将整个字符串按照字典序排序:O(snlog(n))
综上所述:
O(n
slog(s))+O(snlog(n))=O(nslogs+sn*logn)=O(sn(logs+logn))

六,算法复杂度在有些情况是用例相关的

  • 例如插入排序算法O(n^2),最差情况下它的执行是O(n ^ 2),最好情况是O(n),平均情况下是O(n ^ 2)
  • 其他算法同理,一些O(nlogn)级别的算法在一些很恶劣的情况下会退化到O(n^2)级别的算法
  • 严谨的算法分析,需要分析最好和最差的算法复杂度,然而大多数时候,我们需要关注的只是平均的算法复杂度。

本来想打算写关于算法的时间复杂度实验的,现在想想还是放在后面去阐述比较好,所以下面是关于本讲的一个自我检测

  • 算法届讨论的问题是什么?
  • 时间复杂度是什么?
  • 大O与f(n)的关系是什么?
  • 如何去计算算法的时间复杂度?
  • 不同算法的时间复杂度是一个怎样的概念?是否能用图形说明?
  • 学术界和业界对于算法的时间复杂度有怎样的概念?
  • 关于算法的时间复杂度的分析需要注意什么问题?
  • 算法的时间复杂度是与用例相关的吗?如果是,请举出例子

写在最后:依旧,一起进步!!😃

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值