一、数据结构与算法的关系
数据结构与算法是相互依赖,不可分割的。
本书所谈及的算法,为了更好地理解好数据结构,并不会详细谈及算法的方方面面。
二、算法的定义
算法,通俗地讲,是描述解决问题的方法。
如今普遍认可的算法定义是:
算法是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示一个或多个操作。
对于特定的问题,是可以有多种算法来解决的。
三、算法的特性
算法有五个基本特性:输入、输出、有穷性、确定性和可行性。
1、输入:算法有零个或多个输入。
2、输出:算法至少有一个或多个输出。
3、有穷性:指算法在执行有限步骤之后,自动结束而不会出现无限循环,并且每一个步骤在可接受的时间内完成。
4、确定性:算法的每一个步骤都具有确定的含义,不会出现二义性。
5、可行性:算法的每一步都是可行的,即,每一步都能通过执行有限次数完成。
四、算法设计的要求
上面算法的特性,是用来判断是不是算法?再进一步,一个问题,有多种解决方式,即可能有多种解决方法,那我们怎么判断一个算法是不是一个好算法,这就要涉及到算法设计的要求。
1、正确性:算法的正确性是指算法至少应该具有正确输入、输出和加工处理无歧义性、能正确反映问题的需求、能够得到问题的正确答案。
2、可读性:算法设计的另一目的是为了便于阅读、理解和交流。
3、健壮性:当输入数据不合法时,算法也能做出相关的处理,而不是产生异常或莫名其妙的结果。
4、时间效率高和存储量低:好的算法还应该具有时间效率高和存储量低的特点。
综上,好的算法,应该具有正确性、可读性、健壮性、高效率和低存储量的特点。
五、算法效率的度量
我们已经知道了一个好的算法应该具有的特征。刚才我们提到设计算法要提高效率,这里的效率指算法的运行时间,那我们如何度量一个算法的运行时间呢?
度量运行时间,主要有两类方法,事后统计法和事前分析估算法;事后统计方法,主要是通过设计好的测试程序和数据,利用计算机编制的程序的运行时间进行比较,从而确定算法效率的高低。基于事后统计方法有不科学、不准确的缺点,考虑不予采纳,现在更多地是考虑事前分析估算方法 。
事前分析估算方法,即在编程之前,依据统计方法对算法进行估算。
抛开与硬件、软件有关的因素,一个程序的运行时间,依赖于算法的好坏和问题的输入规模。所谓问题的输入规模是指输入量的多少。
由计算1到100的和的两个算法可以看出,测定运行时间最可靠的方法是计算对运行时间有消耗的基本步骤的执行次数。
不关心编写程序用什么语言,在分析程序的运行时间时,最重要的是把程序看成是独立于程序设计语言的算法或一系列步骤。
在分析一个算法时间时,重要的是把基本操作的数量与输入规模并联起来,即基本操作的数量必须表示成输入规模的函数。把基本操作的数量和输入规模并联起来,最直接有效的方式是画出两者的函数图。
六、函数的渐进增长
有时候通过计算算法的基本操作的数量和输入规模,然后作出图,比较繁琐。有没有更简便的方式呢?
函数的渐近增长,是递增函数的一种特性,其定义为:
函数的渐近增长:给定两个函数f(n)和g(n),如果存在一个整数N,使得所有的n>N,f(n)总是比g(n)大,那么,我们说f(n)的增长渐近快于g(n)。
判断一个函数的渐近增长特性,即判断一个算法的效率时,函数中的常数和其他的次要项可以忽略,要关注主项(最高阶项)。
我们发现,如果我们可以对比这几个算法的关键执行次数函数的渐近增长性,基本就可以分析出:某个算法,随着n的增大,它会越来越优于另一个算法,或者越来越差于某个算法。这其实是事前估算方法的理论依据。
七、算法的时间复杂度
在函数的渐近增长的基础上,再进一步介绍一种分析算法时间效率的方法,运用算法时间复杂度进行判断。
算法时间复杂度的定义为:在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。算法的时间复杂度,也就是算法的时间量度,记作:T(n)=O(f(n))。它表示问题规模n的增大,算法执行时间的增长率和f(n)的增长率相同,称作算法的时间复杂度,简称为时间复杂度。其中f(n)是问题规模n的某个函数。
()
推导大O阶:
1、用常数1取代运行时间中的所有加法常数。
2、在修改后的运行次数中,只保留最高阶项。
3、如果最高阶项存在不是1,则去除与这个项相乘的常数。
得到的结果就是大O阶。
八、常见的时间复杂度
常见的时间复杂度及其所耗费的时间从小到大依次为:
O(1)
九、最坏的情况和平均情况
对算法的分析,一种方法是计算所有情况的平均值,这种时间复杂度的计算方法称为平均时间复杂度。另一种方法是计算最坏情况的时间复杂度,这种方法称为最坏时间复杂度。一般在没有说明的情况下,都是指最坏时间复杂度。
举个例子,在一个存储量为n的数据库里查找一个数,最坏的情况是查找了n次才查到这个数,平均的情况是用了n/2次。
最坏情况运行时间是一种保证,那就是运行时间将不会再坏了。在应用中,这是一种最重要的需求,通常,除非特别指定,我们提到的运行时间都是最坏情况的运行时间。
平均运行时间是所有情况中最有意义的,因为它是期望的运行时间。
十、算法空间复杂度
算法的空间复杂度通过计算算法所需的存储空间实现,算法空间复杂度的计算公式记作:S(n)=O(f(n)),其中,n为问题的规模,f(n)为语句关于n所占存储空间的函数。
通常,我们都使用“时间复杂度”来指运行时间的需求,使用“空间复杂度”指空间需求。