python 动态数组 list 内存映射,leetcode 707,真链表能打败假链表吗?

 为什么写这个,我在leetcode刷题(leetcode 707 设计链表 Design Linked List),有个设计链表的题,还特意加了尾指针,也试过双链表,结果时间上还是跑不过别人的直接用list去append和insert的方案,所以随便测一下动态数组list的实现机制。只测了个大概,可能有不严谨的地方或者了解不全面的地方,欢迎指正。

目录

用时对比图

python动态数组list机制探索

如果size不超,难道就不重新分配空间了吗?

从头部删除一个元素,再从头部插入一个元素,是维持原来的内存占用吗?

最骚的操作是,他从来不整体复制,新增的部分确实会开辟新空间,但是原来的元素是不会轻易移动的。

还有删除操作,就算把地址空出来也不会有额外变动

结论:python list高度封装,你能想到的点他基本都处理掉了,建立了访问映射机制,内存分布无论多乱都不影响外部访问。


用时对比图

python动态数组list机制探索

如果size不超,难道就不重新分配空间了吗?


"动态数组的机制是分配一块固定capacity的空间,如果size超出capacity就会重新分配一块更大capacity的空间",死知识是这样的。实际上呢,肯定不是!!!

下面就是一个size一直不超过2,但是内存重新分配的例子。

刚开始应该是分配到栈空间了。加一个元素,删一个元素,动态数组的实现机制,肯定是后延的,最后超出了初始指定的范围以后,直接去堆空间重新划分了一块。

l = [0]
for i in range(1,1000):
    print(l)
    # print(id(l))
    print(id(l[0]))
    l.append(i)
    l.remove(i-1)

所以尾插,删头部,size不增长,和正常使用size增长超过capacity是一个效果。

从头部删除一个元素,再从头部插入一个元素,是维持原来的内存占用吗?

l = [1,2]
print(l)
print(id(l[0]))
print(id(l[1]))
l.remove(1)
print(l)
print(id(l[0]))
l.insert(0,5)
print(l)
print(id(l[0]))
print(id(l[1]))

 

并不是,新的index-0是xxx456,比原来最大的xxx360还大,关键是index-1还维持原来地址,并不同步复制到后边。可以看出,动态数组的实现为了性能的考量,基本上,能不复制能不移动,都是不复制不移动的。

最骚的操作是,他从来不整体复制,新增的部分确实会开辟新空间,但是原来的元素是不会轻易移动的。

l = [-4,-3,-2,0]
for i in range(1,1000):
    print(l)
    # print(id(l))

    l.append(i)
    print(id(l[0]),id(l[1]),id(l[2]),id(l[3]))
    l.remove(i-1)

还有删除操作,就算把地址空出来也不会有额外变动

l = [-4,-3,-2,0]
print(id(l[0]),id(l[1]),id(l[2]),id(l[3]))
l.remove(-2)
print(id(l[0]),id(l[1]),id(l[2]))

==============================================================================================================================================================================================

结论:python list高度封装,你能想到的点他基本都处理掉了,建立了访问映射机制,内存分布无论多乱都不影响外部访问。

假链表所有方面都不输,完全没有多余的复制操作,头尾插入和删除全是O(1),删除指定index也是O(1),而真链表只能O(n)。

所以真链表很难比用动态数组实现的假链表快。不是很难,是不能!吧?

猜你喜欢

转载自blog.csdn.net/huqinweI987/article/details/84181444
今日推荐