第二章 算法
一、算法
1.1 算法的描述
算法
,是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,并且每条指令表示的是一个或多个操作。
比如经典的问题,如何把大象装进冰箱里?
- 把冰箱打开
- 把大象装进冰箱
- 把冰箱关上
上面的描述就构成了一个简单的算法。
1.2 算法的特性
算法拥有五个基本特性:
- 输入输出
- 有穷性
- 确定性
- 可行性
对于算法的输入输入,要求的是算法至少有一个输出,可以没有输入,否则一个不与外界产生交互的算法没有任何意义。
有穷性是指算法的执行要在有限的步骤之下,而有限的步骤又必须在可接受的时间内完成,否则一个30年才能执行完毕的算法很难产生现实意义。
算法的确定性是指,每一个步骤必须是明确的,不能出现二义性,不能像一千个读者就有一千个汉姆雷特那样。
算法的可行性指算法设计的每一步都是具体可执行的,比如我给自己人生设计一个考上清华的算法,但是有一个步骤是每天学习24个小时,这完全就是荒唐了。
1.3 算法设计的要求
对于算法设计的也有五个要求:
- 正确性
- 可读性
- 健壮性
- 时间效率高和存储量低
就比如我们高中做题,一个优秀的解应该满足哪些条件?
第一,它必然是正确的,否则称不上解、也称不上优秀
第二,它必然是可阅读的,老师无法阅读你解的步骤就无法给你真实的评价
第三,它必然是健壮的,当某些不服气的同学拿一些极端情况去攻击你的解法时,你的解法要禁得起考验
第四,它必然要耗时短和足够的简洁,否则也称不上优秀的解嘛,聪明的人还是很多的
把算法特性和算法设计的要求画在一张思维导图上,明确它们之间的区分:
依照我个人的理解,算法的特性是对算法本身的要求,算法设计的要求是对优秀算法的要求。
二、算法效率的度量方法
2.1 事后统计法
事后统计法
,这种方法主要是通过设计好的测试程序和数据,利用计算机定时器对不同算法编制的程序的运行时间进行比较,从而确定算法效率的高低。
这个方法理解起来很简单,就跟运动员比赛跑步一样,同一起点、同一长度的赛道,谁先到终点谁速度快。
这种方法的优点就是简单直观,缺点罗列如下:
- 必须依据算法事先编制好程序,这一般而言要花费的功夫巨大
- 时间的比较依赖计算机硬件和软件等环境因素,有时会掩盖算法本身的优劣
- 算法的测试数据设计困难,并且程序的运行时间往往与测试数据的规模有很大关系
总之,事后估计法并没有被广泛的采纳,而是丢进了历史的垃圾桶里,而一种为今人广为称道的方法是事前分析估计方法。
2.2 事前分析估计方法
事前分析估计方法
,在计算机程序编制前,依据统计方法对算法进行估算。
分析两种求和算法:
第一种算法
int i, sum = 0, n = 100; // 执行1次
for(i=1; i<=n; i++) // 执行n+1次
{
sum = sum + i; // 执行n次
}
printf("%d\n", sum); // 执行1次
:
第二种算法:
int sum = 0, n = 100; // 执行1次
sum = (1 + n) * n/2; // 执行1次
printf("%d\n", sum) // 执行1次
第一种算法一共执行1+(n+1)+n+1=2n+3
次,第二种算法执行1+1+1=3
次,算法的好坏显而易见。
2.3 算法时间复杂度
在进行算法分析时,语句总的执行次数T(n)是关于问题规模n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级。
算法时间复杂度
,也就是算法的时间量度,记作T(n)=O(f(n))。它表示随问题规模n的增大,算法执行的增长率和f(n)的增长率相同,称作算法的渐进时间复杂度,简称时间复杂度,其中f(n)是问题规模n的某个函数。
2.4 推导大O阶方法
推导大O阶:
- 用常数1取代运行时间中的所有加法常数
- 在修改后的运行次数函数中,只保留最高阶项
- 如果最高阶项存在且其系数不是1,则去除与这个项相乘的系数
得到的结果就是大O阶,按照我的理解就是找最高阶,并使最高阶的系数为1,其他项不用考虑。
2.5 常见的时间复杂度
执行次数函数 | 阶 | 非正式术语 |
---|---|---|
12 | O(1) | 常数阶 |
2n+3 | O(n) | 线性阶 |
3n^2+2n | O(n^2) | 平方阶 |
5log(n)+20 | O(log(n)) | 对数阶 |
2n+3nlog(n)+19 | O(nlog(n)) | nlog(n)阶 |
6n3+2n2+3n+4 | O(n^3) | 立方阶 |
2^n | O(2^n) | 指数阶 |
常见时间复杂度耗费时间从小到大排序如下:
O(1)<O(log(n))<O(n)<O(nlog(n))<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
^n | O(2^n) | 指数阶 |
常见时间复杂度耗费时间从小到大排序如下:
O(1)<O(log(n))<O(n)<O(nlog(n))<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)
三、推荐
昨天在下班的路上,偶然看到一个电流表制作的视频,希望对大家的热爱有所帮助。
年轻人的,第二个电流表(完整开源)