算法:是对特定问题求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或者多个操作。
一个算法具有5个重要的特性:
(1)有穷性:一个算法必须总是在执行有穷步之后结束,且每一步都可在有穷时间内完成。
(2)确定性:算法中每一条指令必须有确切的含义,不会产生二义性。并且,在任何条件下,算法只有唯一的一条执行路径,即对相同的输入只能得出相同的输出。
(3)可行性:一个算法是能行的,即算法中描述的操作都是可以通过已实现的基本运算执行有限次来实现的。
(4)输入:一个算法有零个或多个的输入,这些输入取自于某个特定的对象的集合。
(5)输出:一个算法有零个或多个的输出,这些输出是同输入有着某些特定关系的量。
算法设计的要求:
(1)正确性:
(2)可读性:可读性好有助于人对算法的理解
(3)健壮性:当输 入数据非法时,算法也能适当地做出反应或进行处理,而不会产生莫明其妙的输出结果。例如,一个求凸多边形面积的算法,是采用求各三角形面积之和的策略来解决问题的。当输入的坐标集合表示的是一个凹多边形时,不应继续计算,而应报告输入出错。并且,处理出错的方法应是返回一个表示错误或错误性质的值,而不是打印错误信息或异常,并中止程序的执行,以便在更高的抽象层次上进行处理。
(4)效率与低存储量要求:通俗地说,效率指的是算法执行的时间。对于同一个问题如果有多个算法可以解决,执行时间短的算法效率高。存储量需求指算法执行过程中所需要的最大存储空间。效率与低存储量需求这两者都与问题的规模有关。求100个人的平均分与求1000个人的平均分所花的执行时间或运行空间显然有一-定的差别。
算法的性能评价:
算法空间复杂度的计算公式记作:S(n) = O(f(n)),其中n是问题规模,f(n)为语句关于n所占存储空间的函数。
如当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);当一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为O();当一个算法的空间复杂度与n成线性比例关系时,可表示为O(n)。
算法执行时间:一个算法的执行时间大致上等于其所有语句执行时间的总和,对于语句的执行时间是指该条语句的执行次数和执行一次所需时间的乘积。
语句频度:是指该语句在一个算法中重复执行的次数
例如:两个n×n阶矩阵相乘
算法的渐进时间复杂度:原操作是指从算法中选取一种对所研究问题是基本运算的操作,用随着问题规模增加的函数来表征,以此作为时间量度。而对于算法分析,我们关心的是算法中语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。在这里,我们用“O”来表示数量级,这样我们可以给出算法的时间复杂度概念。所谓算法的渐进时间复杂度,即是算法的时间量度,记作: T(n)=O(f(n))
一般情况下,随n的增大,T(n)的增长较慢的算法为最优的算法。
分析的基本策略是从内部(或最深层部分)向外展开工作。
一般法则 :
法则1:for循环
一个for循环的运行时间至多是该for循环内语句的运行时间乘以迭代的次数。
法则2:嵌套循环
从里向外分析嵌套循环。在一组嵌套循环内部的一条语句总运行时间为该语句的运行时间乘以该组所有循环大小的乘积。
法则3:顺序语句
将各个语句的运行时间求和即可(这意味着,其中的最大值就是所得的运行时间)
法则4: if-else语句
一个if-else语句的运行时间从不超过判断再加上if部分和else部分中运行时间较长者的总的运行时间。
例如:(1) x=x+1 ;其时间复杂度为O(1),我们称之为常量阶
(2) for (i=1; i<= n; i++) x=x+1; 其时间复杂度为O(n),我们称之为线性阶
(3) for (i=1; i<= n; i++)
for (j=1; j<= n; j++)
x=x+1; 其时间复杂度为O(n2),我们称之为平方阶
数据结构中常用的时间复杂度频率计数有7个:
一般情况下,随n的增大,T(n)增长较慢的算法为最优的算法。从中我们应该选择使用多项式阶O(nk)的算法,而避免使用指数阶的算法。
常用的时间复杂度频率表:
多种数量级的时间复杂度图示:
例如:下列程序段
for (i=1; i< n; i++)
for (j=i; j<= n; j++)
x++;
有一个二重循环,语句x++的执行频度为:n+(n-1)+(n-2)+…+3+2+1 =n(n+1)/2 而该语句执行次数关于n的增长率为,即时间复杂度为O()。