0. 数据结构与算法之间的关系
数据结构与算法之间存在着本质联系,在某一数据结构上,总要涉及其上施加的运算,
而只有通过对所定义运算的研究,才能清楚理解数据结构的定义和作用;
在涉及运算时,总要联系到该算法处理的对象和结果的数据。
在“数据结构”中,将遇到大量的算法问题,因为算法联系着数据在计算过程的组织方式,
为了描述实现某种操作,常常需要设计算法,因而算法是研究数据结构的重要途径。
- 数据结构是相互之间存在某种关系的数据元素的集合
- 算法是解决特定问题的有限求解步骤
- 数据结构是算法实现的基础,
算法总是要依赖于某种数据结构实现,
设计一种算法时会构建适合于这种算法的数据结构。 - 算法抽象一些,侧重对问题的建模,而数据结构则是具体实现
- 一个想法(算法)需要用实际的东西(数据结构)来实现
==> 用程序解决问题的一般步骤
1. 算法的定义
算法,是为了解决某类问题而规定的一个有限长的操作序列
算法,是解决问题的方法和步骤
-
通俗定义:解题的方法和步骤
-
狭义定义:对存储数据的操作
对不同的存储结构,要完成某一个功能所执行的操作是不一样的
比如,要输出数组中所有的元素的操作 和 要输出链表中所有元素的操作肯定是不一样的
这说明: 算法是依附于存储结构的 不同的存储结构,所执行的算法是不一样的 。
-
广义定义:泛型(C++模板实现)
广义的算法也叫泛型,无论数据是如何存储的,对该数据的操作都是一样的。
广义就是站在一个很高的角度去看待数据操作。
从不同的角度去看待事物,所得到的结论不同。
2. 算法的五大特性
- 有穷性
有穷的步骤,每一步都必须在有穷时间内完成 - 确定性
不会产生二义性,
使算法的执行者或阅读者都能明确其含义及如何执行 - 可行性
算法中的所有操作都可以通过已经实现的
基本操作运算执行有限次来实现 - 输入
一个算法有零个或多个输入 - 输出
一个算法有一个或多个输出,
它们是算法进行信息加工后得到的结果,
无输出的算法是没有任何意义的
3. 评价算法优劣的基本标准
- 正确性
- 可读性
一个好的算法,首先应便于人们理解和相互交流,
其次才是机器可执行性。
可读性强的算法,有助于人们对算法的理解,
而难懂的算法易于隐藏错误,且难以调试和修改 - 健壮性
当输入的数据非法时,好的算法能适应地做出正确反应或进行相应处理,
而不会产生一些莫名其妙的输出结果 - 高效性
高效性包括时间和空间两个方面。
时间高效是指算法设计合理,执行效率高,可以用时间复杂度来度量;
空间高效是指算法占用存储容量合理,可以用空间复杂度来度量;
时间复杂度和空间复杂度时衡量算法的两个主要指标
4. 时间复杂度
-
问题规模
不考虑计算机软硬件等环境因素,影响算法时间代价的最主要的因素是问题规模。
问题规模是算法求解问题输入量的多少,是问题大小的本质表示。
一般用整数 n 表示,问题规模 n 对不同的问题含义不同,
但,n越大算法的执行时间越长(数据规模) -
语句频度 Frequency Count
一个算法的执行时间大致上等于其所有语句执行时间的总和,
而语句的执行时间则为该语句的重复执行次数和执行一次所需时间的乘积。一条语句的重复执行次数,称作 语句频度
由于语句的执行要由源程序经过编译程序翻译成目标代码,
目标代码经过装配再执行,因此语句执行一次实际所需的具体时间是与机器的软硬件环境(例如机器速度、编译程序质量等)密切相关的。
所以,所谓的算法分析并非精确统计算法实际执行所需时间,
而是针对算法中语句的执行次数做出估计,从中得到算法执行时间的信息。设每条语句执行一次所需的时间均是单位时间,
则一个算法的执行时间可用该算法中所有语句频度之和来度量。
相当于提供一个标准、同一比较 -
时间复杂度的定义
为了客观地反映一个算法的执行时间,
可用只用算法中的**“基本语句”的执行次数**来度量算法的工作量。所谓“基本语句”指的是算法中重复执行次数和算法的执行时间成正比的语句,
它对算法运行时间的贡献最大。
贡献程度可以用数量级(Order of Magnitude)来度量。因此,时间复杂度的定义如下:
一般情况下,算法中基本语句重复执行的次数是问题规模 n 的某个函数 f(n),
算法的时间复杂度记作,T(n) = O(f(n))
它表示随着问题规模 n 的增大,算法执行时间的增长率和 f(n) 的增长率相同,
称作算法的渐进时间复杂度,简称时间复杂度(Time Complexity)分析时间复杂度的基本方法:
- 找出所有语句中语句频度最大的那条语句作为基本语句,
- 计算基本语句的频度得到问题规模 n 的某个函数 f(n),
- 取其数量级用符号“O”表示即可
-
最好、最坏和平均时间复杂度
对于某些问题的算法,其基本语句的频度不仅仅与问题规模相关,还依赖于其它因素。
例如,排序算法,其执行时间与待排序记录的初始状态有关,
因此,有时会对算法有最好、最坏以及平均时间复杂度的评价。在最好情况下的时间复杂度,算法计算量可能达到的最小值,称为最好时间复杂度;
在最坏情况下的时间复杂度,算法计算量可能达到的最大值,称为最坏时间复杂度;
算法的平均时间复杂度是指算法在所有可能情况下,按照输入实例以等概率出现时,
算法计算量的加权平均值。对算法时间复杂度的度量,
人们更关心的是最坏情况下和平均情况下的时间复杂度(更有现实意义)。
然而在很多情况下,算法的平均时间复杂度难以确定。
因此,通常只讨论算法在最坏情况下的时间复杂度,
即分析最坏情况下,算法执行时间的上界。“做最坏的打算,去争取最好的结果”,概率问题
5. 空间复杂度
关于算法的存储空间需求,
采用渐进空间复杂度 Space Complexity 作为算法所需存储空间的量度,
简称空间复杂度,它也是问题规模 n 的函数,记作,S(n) = O(f(n))
一般情况下,一个程序在机器上执行时,除了需要寄存本身所用的指令、常数和输入数据外,还需要一些对数据进行操作的辅助存储空间。其中,对于输入数据所占的具体存储量取决于问题本身,与算法无关,这样只需要分析该算法在实现时所需要的辅助空间即可。
若算法执行所需要的辅助空间相对于输入数据量而言是个常数,则称为此算法为原地工作,
辅助空间为O(1)。有的算法需要占用临时的工作单元数与问题规模n有关。
对于一个算法,其时间复杂度和空间复杂度往往是相互影响的,
当追求一个较好的时间复杂度时,可能会导致占用较多的存储空间,
即可能会使空间复杂度的性能变差;反之亦然。
不过,通常情况下,鉴于运算空间较为充足,
人们往往都以算法的时间复杂度作为算法优劣的衡量指标。
6. 算法分析
算法效率分析的目的是看算法实际是否可行,并在同一问题存在多个算法时,
可进行时间和空间性能上的比较,以便从中挑选出较优算法。
衡量算法效率的方法主要有两类:
- 事后统计法
先将算法实现,然后测算其时间和空间的开销。
这种方法的缺陷很显然,一是必须把算法转换成可执行的程序;
二是时空开销的测算结果依赖于计算机软硬件等环境因素,
这容易掩盖算法本身的优劣 - 事前分析法
通常采用事前分析法,通过计算算法的渐进复杂度来衡量算法的效率。