## 算法和算法评价 ### 算法 `算法` : 对特定问题求解步骤的一种描述,**是指令的有序集合**,每一条指令表示一个或多个操作。 #### 重要特性 - `有穷性`:必须总是(对任何合法的输入值)在**执行有穷步后结束**,并且每一步都可**在有穷时间内完成** - `确定性`:每条指令的含义明确,不会产生二义性(歧义),**对相同的输入只能得出相同的结果** - `可行性`:算法是可行的。**算法中描述的操作都是可以通过已经实现的基本运算执行有限次来实现的** - `输入`:有零个或者多个输入,**输入取决于某个特定的对象的集合。** - `输出`:有一个或者多个输出,**输出是和输入有着某种特定关系的量(强调输出与输入的关系)** > **算法是有穷的,但是程序不一定满足有穷性**,程序只是算法在计算机上的特定的实现, 例如:死循环 #### 算法的目标 由于设计思路、解决问题方案等方面不同,不同算法之间也是有好坏的,就像人与人之间存在着差异。为设计出更好的算算法,往往需要追求更高的目标,而好的算法需要考虑到的目标就有: - 正确性:首先算法肯定是**需要正确的解决求解问题** - 可读性:**算法应该具有良好的可读性**,就像项目代码一样,好的业务代码、逻辑清楚,**便于理解**。 - 健壮性:**在输入非法数据时,算法也能适当地做出反应或进行处理,而不会产生莫名奇妙的输出结果**(在高级语言编程中,类似于强调封装方法的参数校验) - 效率与低存储量需求:**效率即算法执行的时间**,**存储量需求即算法那执行过程中所有要的最大存储空间**,这些与算法所解决问题的规模有关; > Tips: 效率可以结合时间复杂度来理解,存储量需求可以结合空间复杂度理解; ### 效率的度量 算法效率的度量是通过`时间复杂度`和`空间复杂度`来描述的; #### 时间复杂度 语句的频度:语句在算法中被重复执行的次数 算法中所有语句的`频度之和`记作T(n),即:对应算法问题规模n的函数,时间复杂度主要是来分析T(n)的数量级; **算法的时间复杂度不仅依赖于问题的规模n,也取决于待输入的数据的性质(例如:输入元素的初始状态)** 上面这句话是不是不能理解??? 哈哈哈,我第一次看,也是!! ```c int test(n) { if(n< 1){ return 0; } // 循环叠加 输出 ..... } ``` 在这个简单的函数里 - 当n<1的时候,例如:-2,就不需要循环,此时时间复杂度可以理解为T(1) - 当n>1的时候,例如:5 此时时间复杂度可以理解为T(n) 当然,这里只是简单举例子便于理解: > **算法的时间复杂度不仅依赖于问题的规模n,也取决于待输入的数据的性质(例如:输入元素的初始状态)** - `最坏时间复杂度`:**最坏情况下**,算法的时间复杂度 - `平均时间复杂度`:**所有可能输入实例在同等概率出现的情况下**,算法的期望运行时间 - `最好时间复杂度`:**最好的情况下**,算法的时间复杂度 一般情况下,考虑最坏情况的时间复杂度(即:最坏时间复杂度),保证算法的运行时间不会更长(最糟糕我都能预料,难道还有更糟糕?????噗呲) #### 空间复杂度 算法的空间复杂度可以用函数记作:S(n),**用来定义算法运行过程中需要耗费的存储空间**,是问题规模n的函数; > 渐进空间复杂度也被称为空间复杂度,记作:S(n)=O(g(n)) **一个程序除了需要存储空间来存放本身所用的指令、常数、变量和输入数据外,也需要对数据进行操作的工作单元和存储一些实现计算所需要信息的辅助空间。** 当输入数据所占用的空间只取决于问题本身,和算法无关时,只需要去分析除了输入和程序之外的额外空间 算法原地工作:算法所需要辅助空间是常量,记作S(1),例如: ```c int switchValue(a,b){ // 定义临时变量 int temp=a; b=temp; a=b; } ``` 在上面的函数中,只是通过临时变量temp来实现a和b的值交换,没有需要更多变量,因此可以简单理解函数的在`原地工作`,辅助空间是常量,记作S(1)