数据结构--知识点1--时间复杂度

一、时间复杂度

1、概念

一个算法的时间复杂度根据算法执行的基本运算数量来衡量
实例解析

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('用时:%d'%(end_time-start_time))

运行结果

204

设时间复杂度为T,则根据执行的步骤得
T=1000 * 1000 * 10002
如果将题目改为a+b+c=2000
T=2000 * 2000 * 2000
2
则设a+b+c=n
T(n)=n3 * 2
如果对程序进行改进:
即c=1000-a-b,减少一次c从0到1000的遍历

import time
start_time=time.time()
for a in range(0,1001):
    for b in range(0,1001):
        c = 1000-a-b
        if  a**2+b**2==c**2:
            print(a,b,c)
end_time=time.time()
print('用时:%d'%(end_time-start_time))

结果:

1

可知,此时时间复杂度为:
T=1000 * 1000 *2=n2 *2

2、大O表示法

根据实例解析,

  • 当没有进行时间缩减时,T(n)=n3 2,
    此时得时间复杂度是一个3次幂的函数,不管它的常数系数是多少,函数的走向不会变,都是n3,因此把它的时间复杂度称为
    g(n)=O(n3);*
  • 同理如果算法的基本运算数量为 *n2 2, 此时时间复杂度为 g(n)=O(n2);
  • 如果算法的基本运算数量为为2,此时因为是常数,因此此时的时间复杂度为g(n)=O(1)

3、最坏时间复杂度

  • 算法完成工作最少需要多少基本操作,即最优时间复杂度
  • 算法完成工作最多需要多少基本操作,即最坏时间复杂度
  • 算法完成工作平均需要多少基本操作,即平均时间复杂度

主要关注最坏时间复杂度,因为它提供了人一种保证,表明算法在此种程度的基本操作中一定能完成工作

4、时间复杂度的基本计算规则

  1. 基本操作,即只有常数,认为其时间复杂度为O(1)
  2. 顺序结构,时间复杂度按加法进行计算
  3. 循环结构,时间复杂度按乘法进行计算
  4. 分支结构,时间复杂度取最大值
  5. 判断一个算法的效率时,往往只需要关注操作数量的最高次项其他次要项和常数项可以忽略
    • 比如3n2 +2*n+1,先忽略常数,得到n2+n,再忽略次要项,得到时间复杂度为O(n2)
  6. 在没有特殊说明时,我们所分析的算法的时间复杂度指最坏时间复杂度

5、最常见的时间复杂度

执行次数函数举例非正式术语
12O(1)常数阶
2n+3O(n)线性阶
3n2+2n+1O(n2)平方阶
5log2n+20O(logn)对数阶
2n+3nlog2n+19O(nlogn)nlogn阶
6n3+2n2+3n+4O(n3)立方阶
2nO(2n)指数阶

注意:经常将log2n(以2为底的对数)简写为logn

6、常见时间复杂度之间的关系

在这里插入图片描述

所消耗的时间从小到大:
O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)<O(2n)<O(n!)<O(nn)

二、python内置类型性能分析

通过时间复杂度分析python内置函数类型的性能

1、timeit模块

timeit模块类似于time.time(),用来测试一小段python代码的执行速度

class timeit.
Timer实例化一个需要测试的实例:
Timer(stmt=‘pass’,setup=‘pass’,timer= < timer function > )

  • Timer是测量小段代码执行速度的类
  • stmt参数是要测试的代码语句(statment,类似于time.time())
  • setup参数是运行代码时需要的设置(类似于import time)
  • timer参数是一个定时器函数,与平台有关

具体测试语句为:
timer.timeit(number=1000000),timer为Timer实例

  • Timer类中测试语句执行速度的对象方法
  • number参数是测试代码时的测试次数,默认为1000000次
  • 方法返回执行代码的平均耗时,一个float类型的秒数

2、创建list实例不同列表创建方法的时间

"""
用timeit模块中的Timer测试构造list的不同方法的性能
1、通过列表相加: li1=[1,2],li2=[23,5] li=li1+li2
2、通过列表生成器:li=[i for i in range(10000)]
3、通过将一个可迭代对象直接转换为列表:li=list(range(10000))
python2中range(100)返回的是列表,如果想要返回可迭代的对象使用xrange(10000)
python3中range(100)返回的是可迭代的对象
4、将值一个一个填充到空列表中:
li=[]
for i in range(10000):
   li.append()
"""
from timeit import Timer


def test1():
    li=[]
    for i in range(10000):
        li.append(i)

def test2():
    li=[]
    for i in range(10000):
        li = li + [i]

def test3():
    li=[i for i in range(10000)]

def test4():
    li=list(range(10000))

def test5():
    # 空列表后直接追加一个完整列表
    li=[]
    for i in range(1000):
        li.extend([i])
def test6():
    # 设置为在列表头部插入
    li =[]
    for i in range(1000):
        li.insert(0,i)

# 需要三个参数
# 第一个为测试的函数,必须是字符串,因为Timer是在其他模块进行测试,需要的参数是代码本身
# 第二个参数是将要测试的内容导入测试模块时需要的设置,因为是当前模块所以__main__
# 第三个参数为timer定时器,根据系统不同而定,一般为默认
timer1=Timer('test1()','from __main__ import test1')
print('append列表尾部追加:',timer1.timeit(1000))
timer2=Timer('test2()','from __main__ import test2')
print('+:',timer2.timeit(1000))
timer3=Timer('test3()','from __main__ import test3')
print('列表生成器:',timer3.timeit(1000))
timer4=Timer('test4()','from __main__ import test4')
print('迭代器直接转换为列表:',timer4.timeit(1000))
timer5=Timer('test5()','from __main__ import test5')
print('extend:',timer5.timeit(1000))
timer6=Timer('test6()','from __main__ import test6')
print('insert列表头部插入:',timer6.timeit(1000))

测试结果:

aappend列表尾部追加: 0.6550495
+: 114.2445353
列表生成器: 0.3527528999999987
迭代器直接转换为列表: 0.2148532000000074
extend: 0.17351130000000126
insert列表头部插入: 0.42504220000000714

从结果可得,最快的是extend方法,最慢的是两个列表相加方法
而相对于append在列表尾部追加和insert在列表头部插入,append尾部追加更快,由python独特的数据结构决定

3、python内置操作的时间复杂度

基本类型只能包括:字符,整型,浮点型等
相对于list,dict相当于一个容器,封装了一些操作,所以不是基本类型

1)list内置操作

Operation大O表示法操作描述
index[ ]O(1)按照索引取值
index assignmentO(1)按照索引赋值
appendO(1)尾部追加元素
pop()O(1)尾部弹出元素
pop(i)O(n)指定位置的元素弹出
insert(i,item)O(n)指定位置插入元素
del operatorO(n)删除,一个一个删除
iterationO(n)迭代
contains(in)O(n)使用in操作符判断某个元素是否在列表中
get slice[x:y]O(k)取x到y之间的切片,k为x~y的距离
del sliceO(n)删除切片,删除某段切片后,需将此切片后的所有元素向前填充
set sliceO(n+k)设置切片位置的值,首先需要将原来切片位置的值删除,再填充所以n+k
reverseO(n)反转
concatenateO(k)将某个列表加到另一个列表中,k为某个列表的长度
sortO(nlogn)排序
multiplyO(nk)列表乘常数,k为常数,n为列表长度

2)dict内置操作

Operation大O表示法操作描述
copyO(n)复制
get itemO(1)取值
set itemO(1)设置某个键
delete itemO(1)删除某个键
contains(in)O(1)查找某个键
iterationO(n)迭代
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值