Python 链表数据结构 理解以及实现

文章目录

  • 1. 为什么Python没有链表数据结构的标准库
    • Python基础数据结构的时间复杂度-List,Set,Dict,Collections.deque
      • (1)List
      • (2)[collections.deque](https://blog.csdn.net/hellojoy/article/details/81281367)
      • (3)set
      • (4)dict
  • 2. Python实现链表

Python 的标准库并没有实现链表这种数据结构的功能,Why?

1. 为什么Python没有链表数据结构的标准库

那么为什么Python作为一种高级语言,却没有实现链表这种数据结构的标准库呢。
实际上刚开始学习一些高级语言的时候我也有同样的疑问,而且即使有链表对应物的语言,链表常常也很少被实际使用(但是在面试过程中却常常被提及,主要是链表数据结构实现简单,却又会很好的考验应聘者的编程思维。)
如果是在国外听数据结构的课,老师一般会警告你这只是一个理论概念,实际应用应该实际考察,在通常情况下链表不是一个很好的结构。
通常链表会作为一个很好的
反例
,告诉大家脱离实际硬件环境来谈论所谓算法复杂度是没有任何意义的。
这是因为,链表已经不适合当今的计算机硬件发展。当今的计算机硬件对内存是否连续更为敏感,而链表恰恰会破坏这种顺序读取。
由于locality很差所以常常造成page fault和cache miss
这也是为什么大多数教师不再推荐使用链表的原因。而且现今的硬件内存拷贝实际相当迅速。
并且Python的list算法不是通常的单项表,也不是通常的数组。
在List末尾append/pop都是O(1)的,如果要在头部或者中部插入是O(n),任何破坏连续性的操作都会被要求realloc,所以任何此类操作都是O(n)

但是当今的常用硬件,使用C写的链表和python的list,在insert的时候只有n>50000才让链表比list快那么一点点。
这还没有考虑其他实际操作的复杂度。加上前面说的破坏locality,导致链表完全没有吸引力。在对象特别多的时候通常我们直接抽象它为数据库,也不要去想什么链表了。

在需要用到linked list特性的地方,比如常常需要从头部append或者pop
这时候有python的deque. deque也不是通常的简单数据结构,它是经过认真权衡过后得到的一种混合式数据结构。

Python基础数据结构的时间复杂度-List,Set,Dict,Collections.deque

该章节翻译自,记录了当前Python中各种操作的时间复杂性(又名“ Big O”或“ Big Oh”)。其他Python实现(或CPython的较早版本或仍在开发中的版本)的性能特征可能略有不同。但是,通常可以假设它们的速度不会超过 O ( l o g n ) O(log n) O(logn)

(1)List

平均情况假设参数是随机随机生成的。

在内部,列表表示为数组。最大的成本来自超出当前分配大小的范围(因为一切都必须移动),或者来自在开始处附近插入或删除某处(因为之后的所有内容都必须移动)。如果需要在两端添加/删除,请考虑改用collections.deque

操作 平均情况 最坏情形
Copy O(n) O(n)
Append O(1) O(1)
Pop last O(1) O(1)
Pop intermediate O(k) O(k)
Insert O(n) O(n)
Get Item O(1) O(1)
Set Item O(1) O(1)
Delete Item O(n) O(n)
Iteration O(n) O(n)
Get Slice O(k) O(k)
Del Slice O(n) O(n)
Set Slice O(k+n) O(k+n)
Extend O(k) O(k)
Sort O(n log n) O(n log n)
Multiply O(nk) O(nk)
x in s O(n)
min(s), max(s) O(n)
Get Length O(1) O(1)

(2)collections.deque

双端队列(双端队列)在内部表示为双链表。(为获得更高的效率,这是数组而不是对象的列表。)两端都是可访问的,但即使看中间也很慢,而向中间添加或从中间删除仍然很慢。Python编程实现

操作 平均情况 最坏情形
Copy O(n) O(n)
append O(1) O(1)
appendleft O(1) O(1)
pop O(1) O(1)
popleft O(1) O(1)
extend O(k) O(k)
extendleft O(k) O(k)
rotate O(k) O(k)
remove O(n) O(n)

(3)set

参见dict-实现与其非常相似。都是key-value结构 但是只有键,value值没有。

操作 平均情况 最坏情形
x in s O(1) O(n)
Union s1t O(len(s)+len(t))
Intersection s&t O(min(len(s), len(t)) O(len(s) * len(t))
Multiple intersection s1&s2&…&sn (n-1)*O(l) where l is max(len(s1),…,len(sn))
Difference s-t O(len(s))
s.difference_update(t) O(len(t))
Symmetric Difference s^t O(len(s)) O(len(s) * len(t))
s.symmetric_difference_update(t) O(len(t)) O(len(t) * len(s))

从源代码中可以看出,设置差异st或s.difference(t)(set_difference())和就地设置差异s.difference_update(t)(set_difference_update_internal())的复杂度不同!第一个是O(len(s))(对于s中的每个元素,如果不在t中,则将其添加到新集合中)。第二个是O(len(t))(对于t中的每个元素,从s中删除它)。因此,必须注意哪个是首选集合,这取决于哪个集合是最长的集合以及是否需要新的集合。

要执行像st这样的设置操作,需要同时设置s和t。但是,即使t是可迭代的,也可以执行方法等效项,例如s.difference(l),其中l是一个列表。

(4)dict

为dict对象列出的平均情况时间假设对象的哈希函数足够强大,以至于不常见冲突。平均情况假设参数中使用的键是从所有键集中随机选择的。

请注意,有一种快速途径可以使dict(实际上)仅处理str键。这不会影响算法的复杂性,但是会显着影响以下恒定因素:典型程序的完成速度。

操作 平均情况 最坏情形
Copy O(n) O(n)
Get Item O(1) O(n)
Set Item O(1) O(n)
Delete Item O(1) O(n)
Iteration O(n) O(n)

2. Python实现链表

你可能感兴趣的:(算法)