数据结构与算法基础Day2

目录

什么是算法?

如何评价算法的好坏?

时间复杂度与空间复杂度

数据结构与算法的区别与关系


什么是算法?

是解决特定问题求解步骤的描述

分析问题,一步一步求解,并得到结果

这一系列的步骤就称之为算法

例如:

如何评价算法的好坏?

1.事后统计法

这种方法主要是通过设计好的程序和数据,利用计算机计时器对不同算法程序的运行时间进行比较,从而确定算法效率的高低。 ​ 弊端: ​ 必须事先编好程序,再进行运行,如果程序处理的数据量较大,则会花费大量的时间和精力 ​ 时间的比较主要依赖于计算机硬件和软件环境 ​ 算法的测试数据设计困难,在数据量较小的时候,不管什么算法其运行时间都是很微小的,相差几乎为零。如果数据量大了,算法的优越性就出来了,但是这样又会耗费时间

2.事前分析法

这种方法主要在计算机程序编制前,依据统计方法对算法进行估算。 ​ 一个高级程序语言编写的程序在计算机上运行时所消耗的时间取决于下列因素: ​ 算法采用的策略、方法——第1条当然是算法好坏的根本 ​ 编译产生的代码质量——第2条取决于具体的编程语言 ​ 问题的输入规模 ​ 机器执行指令的速度——第4条取决于硬件性能 ​ ​ 一个程序的运行时间依赖于算法的好坏和问题的输入规模 所谓问题输入规模是指输数据入量的多少

时间复杂度与空间复杂度

在学习具体的数据结构和算法之前,都需要掌握一个技能,即善于运用时间复杂度和空间复杂度来衡量一个算法的运行效率。

所谓算法,即解决问题的方法。同一个问题,使用不同的算法,虽然得到相同的结果,但耗费的时间和资源肯定有所差异。

所以,如果解决问题的算法有多种,我们就需要从中选出最好的一个。

"好"算法的标准

解决一个问题的方法可能有很多,但称得上算法的,首先它必须能彻底解决这个问题(成为准确性),且根据其编写出的程序在任何情况下都不能崩溃(成为健壮性)。

注意: 程序和算法是完全不同的概念。算法是解决某个问题的想法、思路;而程序实在根据算法编写出来的真正可以运行的代码。

在满足准确性和健壮性的基础上,还有一个重要的筛选条件,即通过算法所编写出的程序的运行效率。程序的运行效率可以从两个方面衡量:

  1. 程序的运行时间

  2. 程序运行所需内存空间的大小

根据算法编写出的程序,运行时间更短,运行期间占用的内存更少,该算法的运行效率就更高,算法也就更好。

数据结构中,用时间复杂度来衡量程序运行时间的多少;用空间复杂度来衡量程序运行所需内存空间的大小

时间复杂度

判断一个算法所编程序运行时间的多少,并不是将程序编写出来,通过在计算机上运行所消耗的时间来度量。原因很简单,一方面,解决一个问题的算法可能有很多种,实现的工作量无疑是巨大的,得不偿失;另一方面,不同的计算机的软、硬件环境不同,即便使用同一台计算机,不同时间段其系统环境也不相同,程序的运行时间很可能会受影响,严重时甚至会导致误判。

实际场景中,我们更喜欢用一个估值来表示算法所编程序的运行时间。所谓估值,即估计的、并不准确的值。注意,虽然估值无法准确的表示算法所编程序的运行时间,但它的得来并非凭空揣测,需要经过缜密的计算后才能得出。

也就是说,表示一个算法所编程序运行时间的多少,用的并不是准确值(无法得出),而是根据合理方法得到的预估值。

预估一个算法所编程序的运行时间,先分别计算程序中每条语句的执行次数,然后用总的执行次数间接表示程序的运行时间。

for(int i = 0 ; i < n ; i++){     //<- 从 0 到 n,执行 n+1 次
    a++;                         //<- 从 0 到 n-1,执行 n 次
}
    整段代码中所有语句共执行了(n+1)+n=2n+1。
    数据结构中,每条语句的执行次数,又被称为该语句的频度。
    整段代码的总执行次数,即整段代码的频度
for(int i = 0 ; i < n ; i++)           // n+1
{ 
    for(int j = 0 ; j < m ; j++)       // n*(m+1)
    {
        num++;                         // n*m
    }
}
    频度:2*n*m+2*n+1

值得一提的是,不同程序的运行时间,更多场景中比较的是在最坏条件下程序的运行时间。以上面这段程序为例,最坏条件即指的是当 n、m 都为无限大时此段程序的运行时间。

要知道,当 n、m 都无限大时,我们完全就可以认为 n==m。在此基础上,2nm+2n+1 又可以简化为 2n²+2n+1,这就是此段程序在最坏情况下的运行时间,也就是此段程序的频度。

如果比较以上 2两段程序的运行时间,即比较 2n+1 和 2n²+2n+1 的大小,显然当 n 无限大时,前者要远远小于后者。显然,第 1 段程序的运行时间更短,运行更快。

以 2n+1 为例,当 n 无限大时,是否在 2n 的基础上再做 +1 操作,并无关紧要,因为 2n 和 2n+1 当 n 无限大时,它们的值是无限接近的。甚至于我们还可以认为,当 n 无限大时,是否给 n 乘 2,也是无关紧要的,因为 n 是无限大,2n 也是无限大。

再以无限大的思想来简化 2n²+2n+1。当 n 无限大的:

    1.首先,常数 1 是可以忽略不计的;
    2.其次,对于指数级的 2n² 来说,是否在其基础上加 2n,并无关紧要;
    3.甚至于,对于是否给 n² 乘 2,也可以忽略。
    4.因此,最终频度 2n²+2n+1 可以简化为 n² 。

也许很多读者对于“使用无限大的思想”简化频度表达式,并不是很清楚。没关系,这里给大家总结一下,在数据结构中,频度表达式可以这样简化:

    1.去掉频度表达式中,所有的加法常数式子。例如 2n²+2n+1 简化为 2n²+2n;
    2.如果表达式有多项含有无限大变量的式子,只保留一个拥有指数最高的变量的式子。例如 2n²+2n 简化为 2n²;
    3.如果最高项存在系数,且不为 1,直接去掉系数。例如 2n² 系数为 2,直接简化为 n²;

事实上,对于一个算法(或者一段程序)来说,其最简频度往往就是最深层次的循环结构中某一条语句的执行次数。例如 2n+1 最简为 n,实际上就是 a++ 语句的执行次数;同样 2n²+2n+1 简化为 n2,实际上就是最内层循环中 num++ 语句的执行次数。

得到最简频度的基础上,为了避免人们随意使用 a、b、c 等字符来表示运行时间,需要建立统一的规范。数据结构推出了大 O 记法(注意,是大写的字母 O,不是数字 0)来表示算法(程序)的运行时间。发展至今,此方法已为大多数人所采纳。

表示方法:

O(频度)

用大 O 记法表示上面两段程序的运行时间,则上面第一段程序的时间复杂度为 O(n),第二段程序的时间复杂度为 O(n²)。

如下列举了常用的几种时间复杂度,以及它们之间的大小关系:

O(1)常数阶 < O(logn)对数阶 < O(n)线性阶 < O(n²)平方阶 < O(n³)(立方阶) < O(2^n) (指数阶)

注意,这里仅介绍了以最坏情况下的频度作为时间复杂度,而在某些实际场景中,还可以用最好情况下的频度和最坏情况下的频度的平均值来作为算法的平均时间复杂度。

空间复杂度

和时间复杂度类似,一个算法的空间复杂度,也常用大 O 记法表示。

要知道每一个算法所编写的程序,运行过程中都需要占用大小不等的存储空间,例如:

    程序代码本身所占用的存储空间;
    程序中如果需要输入输出数据,也会占用一定的存储空间;
    程序中如果需要输入输出数据,也会占用一定的存储空间;

首先,程序自身所占用的存储空间取决于其包含的代码量,如果要压缩这部分存储空间,就要求我们在实现功能的同时,尽可能编写足够短的代码。

程序运行过程中输入输出的数据,往往由要解决的问题而定,即便所用算法不同,程序输入输出所占用的存储空间也是相近的。

事实上,对算法的空间复杂度影响最大的,往往是程序运行过程中所申请的临时存储空间。不同的算法所编写出的程序,其运行时申请的临时存储空间通常会有较大不同。

数据结构与算法的区别与关系

由于大量数据结构教程中都将数据结构的知识和算法掺杂起来讲,使很多初学者认为数据结构就是在讲算法,这样理解是不准确的。

数据结构和算法之间完全使两个相互独立的学科,如果非说它们有关系,那也只是互利共赢、"1+1>2"的关系。

我们可以从分析问题的角度去理清数据结构和算法之间的关系。通常,每个问题的解决都经过以下两个步骤:

1.分析问题,从问题中提取出有价值的数据,将其存储;

2.对存储的数据进行处理,最终得出问题的答案。

数据结构负责解决第一个问题,即数据的存储问题。通过前面的学习我们知道,针对数据不同的逻辑结构和物理结构,可以选出最优的数据存储结构来存储数据。

而剩下的第二个问题,属于算法的职责范围。算法,从表面意思来理解,即解决问题的方法。我们知道,评价一个算法的好坏,取决于在解决相同问日的前提下,哪种算法的效率最高,而这里的效率指的就是处理数据、分析数据的能力。

因此,我们得出这样的结论,数据结构用于解决数据存储问题,而算法用于处理和分析数据,它们是完全不同的两类学科。

也正因为如此,你可以认为数据结构和算法存在"互利共赢"的关系。在解决问题的过程中,数据结构要配合算法选择最优的存储结构来存储数据,而算法也要结合数据存储的特点,用最优的策略来分析并处理数据,由此可以最高效地解决问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Illus1ion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值