算法的概念
算法是计算机处理信息的本质,因为计算机程序本质上是⼀个算法来告诉计算机确切的步骤来执⾏⼀个指定的任务。⼀般地,当算法在处理信息时,会从输⼊设备或数据的存储地址读取数据,把结果写⼊输出设备或某个存储地址供以后再调⽤。
算法是独⽴存在的⼀种解决问题的⽅法和思想。
对于算法⽽⾔,实现的语⾔并不重要,重要的是思想。
算法可以有不同的语⾔描述实现版本(如C描述、C++描述、Python描述等),我们现在是在⽤Python语⾔进⾏描述实现。
算法的五⼤特性
- 输⼊: 算法具有0个或多个输⼊
- 输出: 算法⾄少有1个或多个输出
- 有穷性: 算法在有限的步骤之后会⾃动结束⽽不会⽆限循环,并且每⼀个步骤可以在可接受的时间内完成
- 确定性:算法中的每⼀步都有确定的含义,不会出现⼆义性
- 可⾏性:算法的每⼀步都是可⾏的,也就是说每⼀步都能够执⾏有限的次数完成
时间复杂度与“⼤O记法”
我们假定计算机执⾏算法每⼀个基本操作的时间是固定的⼀个时间单位,那么有多少个基本操作就代表会花费多少时间单位。显然对于不同的机器环境⽽⾔,确切的单位时间是不同的,但是对于算法进⾏多少个基本操作(即花费多少时间单位)在规模数量级上却是相同的,由此可以忽略机器环境的影响⽽客观的反应算法的时间效率。
对于算法的时间效率,我们可以⽤“⼤O记法”来表示。
“⼤O记法”
对于单调的整数函数f,如果存在⼀个整数函数g和实常数c>0,使得对于充分⼤的n总有f(n)<=c*g(n),就说函数g是f的⼀个渐近函数(忽略常数),记为f(n)=O(g(n))。也就是说,在趋向⽆穷的极限意义下,函数f的增⻓速度受到函数g的约束,亦即函数f与函数g的特征相似。
时间复杂度
假设存在函数g,使得算法A处理规模为n的问题示例所⽤时间为T(n)=O(g(n)),则称O(g(n))为算法A的渐近时间复杂度,简称时间复杂度,记为T(n)。
如何理解“⼤O记法”
对于算法进⾏特别具体的细致分析虽然很好,但在实践中的实际价值有限。对于算法的时间性质和空间性质,最重要的是其数量级和趋势,这些是分析算法效率的主要部分。⽽计量算法基本操作数量的规模函数中那些常量因⼦可以忽略不计。例如,可以认为3n2 和100n2 属于同⼀个量级,如果两个算法处理同样规模实例的代价分别为这两个函数,就认为它们的效率“差不多”,都为n2 级。
最坏时间复杂度
分析算法时,存在⼏种可能的考虑:
算法完成⼯作最少需要多少基本操作,即最优时间复杂度
算法完成⼯作最多需要多少基本操作,即最坏时间复杂度
算法完成⼯作平均需要多少基本操作,即平均时间复杂度
对于最优时间复杂度,其价值不⼤,因为它没有提供什么有⽤信息,其反映
的只是最乐观最理想的情况,没有参考价值。
对于最坏时间复杂度,提供了⼀种保证,表明算法在此种程度的基本操作中
⼀定能完成⼯作。
对于平均时间复杂度,是对算法的⼀个全⾯评价,因此它完整全⾯的反映了这个算法的性质。但另⼀⽅⾯,这种衡量并没有保证,不是每个计算都能在这个基本操作内完成。⽽且,对于平均情况的计算,也会因为应⽤算法的实例分布可能并不均匀⽽难以计算。
因此,我们主要关注算法的最坏情况,亦即最坏时间复杂度。
时间复杂度的⼏条基本计算规则
- 基本操作,即只有常数项,认为其时间复杂度为O(1)
- 顺序结构,时间复杂度按加法进⾏计算
- 循环结构,时间复杂度按乘法进⾏计算
- 分⽀结构,时间复杂度取最⼤值
- 判断⼀个算法的效率时,往往只需要关注操作数量的最⾼次项,其它次要项和常数项可以忽略
- 在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度