今天是学Python算法的第1天,第一卷:起行。

目录
题引
如果将最终写好运行的程序比作战场,
我们便是指挥作战的将军,
而我们所写的代码便是士兵和武器。
那么数据结构和算法是什么?
答曰:兵法!
序言
有这样一道题:
有三个自然数,a,b,c,已知a+b+c=100,且a^2+b^2+c^2=100,求a,b,c,所有的组合。
这个问题我们应该怎么解决?第一想法:一个个试------即枚举法。
所以这时我们的思路为:a=0,b=0,c从0试验到1000,符合a^2+b^2+c^2=100就写下来,一轮试过后,再改变a或b的一个变量,继续试验......
less
# 普通算法
import time
start_time = time.time()
for a in range(0,1001):
for b in range(0,1001):
for c in range(0,1001):
if a+b+c == 1000 and a**2 + b**2 == c**2:
print(a,b,c)
end_time = time.time()
print("time:%d"%(end_time-start_time))

章一:悟透韬略------概念
算法是计算机处理信息的本质,因为计算机程序本质上是一个算法来告诉计算机确切的步骤来执行一个指定的任务。一般地,当算法在处理信息时,会从输入设备或数据的存储地址读取数据,把结果写入输出设备或某个存储地址,供以后再调用。
算法是独立存在的****一种解决问题的方法和思想 ,如序言中的枚举法。
对于算法而言,实现的语言并不重要,重要的是思想 。
算法可以有不同的语言描述实现版本(如c描述,c++描述,Python描述等),我现在是在用Python语言进行描述实现。
章二:洞晓玄机------特性
1.输入
算法具有0个或多个输入。
2.输出
算法至少有一个或多个输出。
3.有穷性
算法在有限的步骤之后会自动结束而不会无限循环,并且每一个步骤可以在可接受的时间内完成。
4.确定性
算法中的每一步都有确定的含义,不会出现二义性。
5.可行性算法的每一步都是可行的,也就是说每一步都能够执行有限的次数完成。
章三:优胜劣汰------优化
优化序言中题目的思路:
因为当a,b确定时,c也能确定,所以可以改进程序。
less
import time
start_time = time.time()
for a in range(0,1001):
for b in range(0,1001):
c = 1000 - a - b
if a+b+c == 1000 and a**2 + b**2 == c**2:
print(a,b,c)
end_time = time.time()
print("time:%d"%(end_time-start_time))

对于同一问题我们给出了两种解决算法,在两种算法的实现中,我们对程序执行的时间进行了测算,发现两段程序执行的时间相差悬殊(202秒相较于0秒)。
由此我们可以得出结论:实现算法程序的执行时间可以反映出算法的效率,即算法的优劣。
章四:统一度量衡------时间复杂度
1.引入
如果我们将第二次尝试的算法程序运行在一台配置古老,性能低下的计算机中,情况会如何?
所以,单纯依靠运行的时间比较算法的优劣并不一定是客观准确的!
于是,我们应该统一度量衡。
因为每台机器执行的总时间不同,但是执行基本运算数量大体相同,如上面的例题,T=N*N*N*2,所以T(n)=n^3*2,所以我们把这个T(n)的函数叫做这个算法的时间复杂度。
2.定义假设存在函数g,使得算法A处理规模为n的问题示例所用时间为T(n)=O(g(n)),则称为O(g(n))为算法A的渐进时间复杂度,简称时间复杂度,记为T(n)。
对于算法的时间效率,我们可以用"大O记法"来表示。
3.大O记法
对于单调的整数函数f,如果存在一个整数函数g和实常数c(c>0),使得对于充分大的n,总有f(n)<=c*g(n),就说函数g是f的一个渐进函数(忽略常数),记为f(n)=O(g(n)).也就是说在趋向无穷的极限意义下,函数f的增长速度受到函数g的约束,亦即函数f与函数g的特征相似。
4.时间复杂度分类
分析算法时,存在几种可能的考虑:
- 算法完成工作最少需要多少基本操作,即最优时间复杂度;
- 算法完成工作最多需要多少基本操作,即最坏时间复杂度;
- 算法完成工作平均需要多少基本操作,
- 即平均时间复杂度。
对于最优时间复杂度,其价值不大,因为它没有
提供什么有用信息,其反映的只是最乐观最理想的情况,没有参考价值。
对于最坏时间复杂度,提供了一种保证,表明算法在此种程度的基本操作中一定能完成工作。
对于平均时间复杂度,是对算法的一个全面评价,因
此它完整的全面的反映了这个算法的性质。但另一方面,这种衡量并没有保证,不是每个计算都能在这个基本操作内完成。而且,对于平均情况的计算,也会因为应用算法的实力分布可能并不均匀而难以计算。
因此,我们主要关注算法的最坏情况,亦即最坏时间复杂度。
5.几条基本计算规则
1.基本操作,即只有常数项,认为其时间复杂度为O(1)
2.顺序结构,时间复杂度按加法进行计算。
3.循环结构,时间复杂度按乘法进行计算。
4.分支结构,时间复杂度取最大值。
5.判断一个
算法的效率时,往往只需要关注操作数量的最高次项,其它次要项和常数项可以忽略。
6.在没有特殊说明时,我们所分析的算法的时间复杂度都是指最坏时间复杂度。
6.计算
所以,序言中的题目,第一次的时间复杂度为:T(n)=O(n*n*n)=O(n^3),第二次的时间复杂度为:T(n)=O(n*n*(1+1))=O(n*n)=O(n^2)
由此可见第二种的算法要比第一种的算法时间复杂度好。
7.常见的时间复杂度
注意:经常将以二为底的对数简写为log n
具体大小关系可以见下图:

所消耗的时间大小从小到大(要背诵):
O(1)<O(log n)<O(n)<O(nlog n)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)
章五:如虎添翼------timeit模块
timeit模块可以用来测试一小段Python代码的执行速度。
arduino
class timeit.Timer(stmt = 'pass',setup = 'pass',timer = <timer function>
Timer是测量小段代码执行速度的类;
stmt参数是要测试的代码语句(statment);
setup参数是运行代码时需要的设置;
timer参数是一个定时器函数,与平台有关。
ini
import timeit
timeit.Timer.timeit(number=1000000)
Timer类中测试语句执行速度的对象方法。number参数是测量代码时的测量次数,默认为1000000次。方法返回执行代码的平均耗时是一个float类型的秒数。
尾声
数据结构和算法是一名程序开发人员的必备基本功,不是一朝一夕就能练成绝世高手的。冰冻三尺非一日之寒,需要我们平时不断的主动去学习积累。
(未完待续)