[数据结构与算法笔记](一)Python引入时间复杂度与大O表示法

引入

例1 如果a+b+c=1000,且a^2+b^2=c^2(a、b、c为自然数),如何求出a,b,c所有的可能性?
直觉:采用枚举法
思路:
a=0
b=0
c=0~1000

import time
start=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:%d,%d,%d"%(a,b,c))
end=time.time()
print ("time:%d"%(end-start))               

运行结果如下:

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:97

注:Ubuntu的CPU使用率命令:top

算法的提出

算法的概念

算法是计算机处理信息的本质,算法是独立存在的一种解决问题的方法和思想。
(实现的语言不重要,重要的是思想
参考书:数据结构与算法Python语言描述 裘宗燕著

算法的五大特性

1.输入
2.输出
3.有穷性(有限的步骤&有限的时间)
4.确定性(每一步都有确切的含义)
5.可行性 (每一步执行有限的次数可以结束)

时间复杂度与大O表示法

还是例1。
考虑c是由ab确定好的,因此使c=1000-a-b,可以去掉a+b+c=1000的判断条件。程序设计如下:

import time
start=time.time()
for a in range(0,1001):
    for b in range(0,1001):
        c=1000-a-b
        #for c in range(0,1001):
        if a**2+b**2==c**2:
            print ("a,b,c:%d,%d,%d"%(a,b,c))
end=time.time()
print ("time:%d"%(end-start))               

运行结果:

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

最终执行时间不到1s。
可以发现改变算法后代码运行的时间大大减小,说明算法之间有优劣。
但是只用时间来衡量可信吗?
比如运行在古老的机器上的时候,计算量大的时候计算时间会增多,为了评判算法的优劣,因此引入时间复杂度概念

一段同样的程序在两台不同的机器上运行时间可能有差别,但是执行基本运算数量大体相同,比如老机器一步需要几毫秒,而新的机器一步只要几微秒。通过计算运算步骤数量衡量算法优劣,因此引入时间复杂度。

假设一个算法的规模是n,例如a+b+c=1000,n=1000就是上面算法的规模,完成这个算法的步骤T(n)=n*n*3(假设循环里面一行代码就是一个步骤)那么T(n)=n^2*3就是时间复杂度
如果底下的代码不是3行,是10行。则时间复杂度为T(n)=n^2*10。

为了方便描述,用大O记法,类似与高数里面的高阶无穷小o(n),也许就叫渐进函数吧,去掉系数与常数项,保留特征项n^2,因此上面算法的时间复杂度为O(n^2)。

最坏时间复杂度与计算规则

最坏时间复杂度

算法完成工作最少需要多少基本操作,即最优时间复杂度,反之最坏时间复杂度
最优时间复杂度只是最乐观理想情况,没有参考价值。
因此最坏时间复杂度提供一种保证,表明算法在此程度的基本操作中一定完成任务。

时间复杂度的计算规则
  • 基本操作,即只有常数项,算法复杂度为O(1)
  • 顺序,条件,循环可以代表所有语言的基本步骤。顺序结构的算法复杂度按加法进行计算,循环结构乘法计算,分支结构取算法复杂度的最大值(例如两条分支的算法复杂度不同,考虑最坏的情况,因此取算法复杂度的最大值)
  • 只关注最高次项
  • 没有特殊说明,我们分析的就是算法的最坏算法复杂度

常见的时间复杂度

这里写图片描述
O ( 1 ) < O ( l o g n ) < O ( n ) < O ( n l o g n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n )

代码执行时间测量模块timeit

衡量函数调用,函数中封装了非常多的基本步骤,因此python一行代码有可能不是一个基本步骤。

引入python内置类型性能分析:timeit模块

class timeit.Timer(stmt='pass',setup='pass',time=<timer function>)

Timer是测量一小段代码执行速度的类。
stmt是要测量的代码语句(statement),一般是将函数名换成字符串。
setup参数是运行代码时需要的设置,一般指需要导入的包操作等,如果是从当前文件中导入XXX函数则需要写from __main__ import XXX
timer参数是一个定时器函数,一般不用管。

timeit.Timer.timeit(number =1000000)

Timer.timeit是Timer类中测试语句执行速度的对象方法,number参数是测试代码的测试次数,默认100W次,返回float类型的秒数,即执行代码的平均耗时。

Python列表类型不同操作的时间效率

对于列表:

import timeit
li1=[1.2]
li2=[23,5]
li=li1+li2
li=[li for i in range(10000)]
li=list(range(10000))
#python2与python3中range()的区别:python2中的range为一个列表对象,而
#python3中的range是一个可迭代对象,而python2中想要可迭代对象,就要使用
#xrange
def test1():
    li=[]
    for i in range(10000):
        li.append(i)
def test2():
    li=[]
    for i in range(10000):
        li+=[i]

猜你喜欢

转载自blog.csdn.net/weixin_39449466/article/details/80413948
今日推荐