【数据结构基础】时间复杂度

1 引入

        我们知道,一个程序的好坏,应该至少要满足bug少,效率高,所占空间小,可读性强,以及一些好的习惯

        而本篇所讲的就关乎于效率问题

        不知道是不是真的哈,据说《道德与法治5OL》以前的加载时间巨长,启动的时候需要跑19.8亿次循环的if语句(这里挂上链接 你见过的最烂的代码长什么样子?),其实这就是R星的程序员没有关注这个地方的时间复杂度所造成的问题,可见时间复杂度的学习有多重要。

2 什么是时间复杂度

        简单来讲,时间复杂度就是一个函数(数学意义上的函数),这个函数用于表示一个程序或者一串代码运行完所需要的时间量级

        我们来看一段代码

void fun(int n)
{
    int count = 0;
    for(int i = 0; i < n; i++)
    {
        count++;
    }
}

        这里count在循环里不断 ++ 了 n 次,记作T(N)

        注意:这里其实我们不关注循环里面的内容,因为循环里面的内容不管是什么对于CPU来说都是一瞬间就可以完成的事,所以我们只关注循环次数而非循环里的内容

        再比如这个函数

void fun(int n)
{
	int count = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			count++;
		}
	}
}

        这里count ++ 了 n^2 次,那么这里就是 T(N^2)

        再比如这个函数

void fun(int n)
{
	int count = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			count++;
		}
	}
	for (int p = 0; p < n; p++)
	{
		count++;
	}

        这里count ++ 了 N^2 + N 次,那就是T(N^2 + N)

        所以简单来说,T(?) 就是用来表示这段代码循环了多少次的

3 大O记法的引入

        注意看时间复杂度的定义,我着重标注了时间量级这是因为在绝大多数情况下,其实比较具体次数是没有意义的,我们只能用抽象的时间量级来比较

        比方说以下三段代码

void fun(int n)
{
	int count = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			count++;
		}
	}
	for (int p = 0; p < n; p++)
	{
		count++;
	}
}
void fun(int n)
{
	int count = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			count++;
		}
	}
}
void fun(int n)
{
	int count = 0;
	for (int i = 0; i < n; i++)
	{
			count++;
	}
}

        不难看出一个是T(N^2 + N),第二个是P(N^2),第三个是Q(N)

        现在我们往N代入数字

NT(N^2 + N)P(N^2)Q(N)
530255
1011010010
1000100100010000001000
1000000100000100000010000000000001000000

        不难发现N在不断增大的同时,带了N^2的增速要比不带N^2的快不少,每次增加1,两者相差都会大更多,而两个带N^2的增速就差不多了,每次增加1,两者相差都只大了1而已,如果这三个函数实现的效果相当并且N = 1000000 的话,那么对于计算机来讲,P(N^2) 就要比 T(N^2 + N) 少算1000000 次,但 Q(N) 就要比 T(N^2 + N) 少算 1000000000000 次!对于现代的CPU来说,多算1000000 次问题不大,但多算 1000000000000 那问题就大了!!

        所以借此,我们引入了一种新的估算记法,即大O记法

注意:为什么我们不考虑N很小的时候??

        因为当N很小时,这三个函数的执行时间都非常非常小,小到可以忽略不计,所以我们一般不讨论N很小时的情况

这里再提一嘴循环里的内容,如果循环里面再加一行例如 num++ 的代码,那么 N 的前面应该多一个系数2,例如 T(N^2) 变成 T(2*N^2),只是这里的系数对整个运算过程的影响依旧太小了(有兴趣可以代数字推导一下)所以我们一般不关注系数

4 大O记法

        其实本质上就是时间量级

        所谓“量级”,就是某几个东西的差距大到无论怎么比较,一方总是碾压另一方,比方说自行车的速度再怎么快,你也赶不上火车,火车再怎么快,你也赶不上火箭,火箭再怎么快,你也赶不上光速,光速再怎么快,你也赶不上虫洞(空间跳跃)

        前面我们看到的三个函数,你会发现N很大时 T(N^2 + N) 所花的时间和  P(N^2) 差不多,而 T(N^2 + N) 所花的时间要比 Q(N) 多上很多,这就是因为前俩时间量级是相同的,后俩时间量级不同,不难发现前俩能花这么长时间的根本原因就是因为 N 带上了平方,而除了 N^2 外的其他因素就都可以忽略不计了(比方说自行车改装得再怎么好,你也赶不上一列全速前进的火车),所以前俩的时间量级就都是 N^2 ,记作 O(N^2) ,而 最后一个函数的时间量级就是 O(N) ,所以大O记法的最大特征就是不能直接计算“次数”,而是用 “时间量级” 来评判一串代码效率是否高。

        所以这里不管如何,O(N^2) 再怎么快,你的效率也追不上 O(N)

        那我们称 O(?) 为大 O 阶,而阶也分为很多种,我们接着看

注意:其实大O记法就是取多项式里增速最快的一项,因为不关注系数,所以还要把系数也一并省略掉

5 常见的阶

执行次数举例别称
18(任意常数)O(1)常数阶
2N + 3O(N)线性阶
3*N^2 + 3O(N^2)平方阶
3log2 N + 6O(logN)对数阶
3N*log2 NO(NlogN)nlogn阶
N^3 + 1O(N^3)立方阶
2^N + 6N + 1O(2^n)指数阶

        事实上,我们常用到的阶并不多,一般也就用用常数阶,线性阶,平方阶,对数阶,剩下的阶几乎很少用,因为效率太低了,会对程序运行速度产生很大影响

6 最坏情况和平均情况

        现在我们看看以下代码

char* fun(char* str, char ch)
{
	while (str != NULL)
	{
		if (*str == ch)
		{
			return str;
		}
		else
		{
			str++;
		}
	}
}

         这个代码其实就是用来找一个字符串里面有没有想要找的字符

        不难看出其实这里执行次数是根据参数在动态变化的

最好情况O(1)
最坏情况O(N)
平均情况O(N)   (1/2 * N次)

        遇到这种不确定执行次数的情况下,一般我们都保守估计最坏情况来评判代码的效率,用平均情况来说明其期望运行时间,当然哈,写代码的时候肯定要做最坏的打算的,最坏你也得符合预期

  • 38
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值