数据结构和算法是一名程序开发人员的必备基本功,不是一朝一夕就能练成绝世高手的。冰冻三尺非一日之寒,需要我们平时不断的主动去学习积累。
先来看一道题:
如果 a+b+c=1000,且 a^2 + b ^2 = c^2(a,b,c 为自然数),如何求出所有a、b、c可能的组合?
我们使用穷举法和枚举来分析:
循环遍历 a b c 满足条件的输出。代码如下:
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**2 + b**2 == c**2 and a+b+c == 1000:
print("a, b, c: %d, %d, %d" % (a, b, c))
# 记录结束时间
end_time = time.time()
# 打印消耗的时间
print("time: %f" % (end_time - start_time))
运行的结果是:
a, b, c: 0, 500, 500
a, b, c: 200, 375, 425
a, b, c: 375, 200, 425
a, b, c: 500, 0, 500
time: 1240.802592
我们看到运行代码消耗的时间为:1240.802592
算法的概念:
算法是计算机处理信息的本质,因为计算机程序本质上是一个算法来告诉计算机确切的步骤来执行一个指定的任务。一般地,当算法在处理信息时,会从输入设备或数据的存储地址读取数据,把结果写入输出设备或某个存储地址供以后再调用。
算法是独立存在的一种解决问题的方法和思想。
对于算法而言,实现的语言并不重要,重要的是思想。
算法可以有不同的语言描述实现版本(如C描述、C++描述、Python描述等),我们现在是在用Python语言进行描述实现。
当我们遍历完a 、 b, 根据条件得知 a+b+c=1000, 所以我们不用再去遍历c, c=1000-a-b
修改后代码如下:
import time
start_time = time.time()
for a in range(0, 1001):
for b in range(0, 1001-a):
# 这里直接可以由a和b得出c
c = 1000 - a - b
# 因为上面已经得出c=1000-a-b,所以这里不再判断a+b+c == 1000
if a**2 + b**2 == c**2:
print("a, b, c: %d, %d, %d" % (a, b, c))
end_time = time.time()
print("time: %f" % (end_time - start_time))
运行的结果是:
a, b, c: 0, 500, 500
a, b, c: 200, 375, 425
a, b, c: 375, 200, 425
a, b, c: 500, 0, 500
time: 0.667052
我们看到运行代码消耗的时间为:0.667052
对于同一问题,我们给出了两种解决算法,在两种算法的实现中,我们对程序执行的时间进行了测算,发现两段程序执行的时间相差悬殊(1240.802592秒相比于0.667052秒),由此我们可以得出结论:实现算法程序的执行时间可以反应出算法的效率,即算法的优劣
假设我们将第二次尝试的算法程序运行在一台配置古老性能低下的计算机中,情况会如何?很可能运行的时间并不会比在我们的电脑中运行算法一的214.583347秒快多少。
单纯依靠运行的时间来比较算法的优劣并不一定是客观准确的!
程序的运行离不开计算机环境(包括硬件和操作系统),这些客观原因会影响程序运行的速度并反应在程序的执行时间上。那么如何才能客观的评判一个算法的优劣呢?
我们假定计算机执行算法每一个基本操作的时间是固定的一个时间单位,那么有多少个基本操作就代表会花费多少时间单位。显然对于不同的机器环境而言,确切的单位时间是不同的,但是对于算法进行多少个基本操作(即花费多少时间单位)在规模数量级上却是相同的,由此可以忽略机器环境的影响而客观的反应算法的时间效率。
基本运算总数 x 基本运算的单位时间
然后来分析上面的代码:
第一中时间复杂度为T1=10001000100010
第二种时间复杂度为T2=10001000*10
通过T1和T2,可以明显的对比出哪个算法更优。
T是什么? 这就引出了我们的概念 时间复杂度与“大O记法” 下一节继续。。