Python中顺序表的算法复杂度

一.算法复杂度的引入

  1. 对于算法的时间和空间性质,最重要的是其量级和趋势,所以衡量其复杂度的函数常量因子可以忽略不计.
  2. 大O记法通常是某一算法的渐进时间复杂度,常用的渐进复杂度函数复杂度比较如下:
    O(1)<O(logn)<O(n)<O(nlogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n)

     

  3. 引入时间复杂度的例子,请比较两段代码的例子,看其计算的结果
    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 :%d, %d, %d" % (a, b ,c))
    end_time = time.time()
    print("times:%d" % (end_time-start_time))
    print("完成")

    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 :%d, %d, %d" % (a, b ,c))
    end_time = time.time()
    print("times:%d" % (end_time-start_time))
    print("完成")

  4. 如何计算时间复杂度:

    # 时间复杂度计算
    # 1.基本步骤,基本操作,复杂度是O(1)
    # 2.顺序结构,按加法计算
    # 3.循环,按照乘法
    # 4.分支结构采用其中最大值
    # 5.计算复杂度,只看最高次项,例如n^2+2的复杂度是O(n^2)

     

二.顺序表的时间复杂度

  1. 列表时间复杂度的测试
    # 测试
    from timeit import Timer
    
    def test1():
        list1 = []
        for i in range(10000):
            list1.append(i)
            
    def test2():
        list2 = []
        for i in range(10000):
            # list2 += [i] # +=本身有优化,所以不完全等于list = list + [i]
            list2 = list2 + [i]
            
    def test3():
        list3 = [i for i in range(10000)]
        
    def test4():
        list4 = list(range(10000))
        
    def test5():
        list5 = []
        for i in range(10000):
            list5.extend([i])
        
    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("[i for i in range]:",timer3.timeit(1000))
    
    timer4 = Timer("test4()","from __main__ import test4")
    print("list(range):",timer4.timeit(1000))
    
    timer5 = Timer("test5()","from __main__ import test5")
    print("extend:",timer5.timeit(1000))

    输出结果

  2. 列表中方法的复杂度:

    # 列表方法中复杂度
    # index    O(1)
    # append    0(1)
    # pop    O(1) 无参数表示是从尾部向外取数
    # pop(i)    O(n) 从指定位置取,也就是考虑其最复杂的状况是从头开始取,n为列表的长度
    # del    O(n) 是一个个删除
    # iteration O(n)
    # contain O(n) 其实就是in,也就是说需要遍历一遍
    # get slice[x:y] O(K)   取切片,即K为Y-X
    # del slice O(n) 删除切片
    # set slice O(n) 设置切片
    # reverse O(n) 逆置
    # concatenate O(k) 将两个列表加到一起,K为第二个列表的长度
    # sort O(nlogn) 排序,和排序算法有关
    # multiply O(nk) K为列表的长度

     

  3. 字典中方法的复杂度(补充)
    # 字典中的复杂度
    # copy O(n)
    # get item O(1)
    # set item O(1) 设置
    # delete item O(1)
    # contains(in) O(1) 字典不用遍历,所以可以一次找到
    # iteration O(n)

     

 三.顺序表的数据结构

 

 

  1. 一个顺序表的完整信息包括两部分,一部分是表中的元素集合,另一部分是为实现正确操作而需要记录的信息这部分信息主要包括元素存储区的容量和当前表中已有的元素个数两项。 
  2. 表头和数据区的组合:一体式结构:表头信息(记录容量和已有元素个数的信息)和数据区做连续储存 
  3. 分离式结构:表头信息和数据区并不是连续存储的,会多处一部分信息用来存储地址单元,用来指向真实的数据区
  4. 两者差别和优劣:
# 1.一体式结构:数据必须整体迁移
# 2.分离式结构:在数据动态的过错中有优势
# 申请多大的空间?
# 扩充政策:
# 1.每次增加相同的空间,线性增长
# 特点:节省空间但操作次数多
# 2.每次扩容加倍,例如每次扩充增加一倍
# 特点:减少执行次数,用空间换效率


# 数据表的操作:
# 1.增加元素:
# a.尾端加入元素,时间复杂度为O(1)
# b.非保序的元素插入:O(1)
# c.保序的元素插入:时间度杂度O(n)(保序不改变其原有的顺序)


# 2.删除元素:
# a.末尾:时间复杂度:O(1)
# b.非保序:O(1)
# c.保序:O(n)

# python中list与tuple采用了顺序表的实现技术

# list可以按照下标索引,时间度杂度O(1),采用的是分离式的存储区,动态顺序表

 

 

四. python中变量空间扩充的策略


1.在建立空表(或很小的表)时,系统分配的是一块能容纳8个元素的存储区
2.在执行插入操作(insert,append)时,如果元素存储区满就换一块四倍大的存储区
3.如果此时的表已经很大(阀值是50000),则改变政策,采用加一倍的方法。为了避免出现过多空闲的空间。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值