如何在Python中使用O(1)查找列表元素?

时间:2018-10-07 02:33:29

标签: python arrays list big-o

今天在课堂上,我们了解到在Python中从列表中检索元素是O(1)。为什么会这样呢?假设我有四个项目的列表,例如:

li = ["perry", 1, 23.5, "s"]

这些项目在内存中具有不同的大小。因此,不可能取li[0]的存储位置并添加每个元素大小的三倍来获得li[3]的存储位置。那么,解释器如何知道li[3]的位置而不必遍历列表以检索元素?

3 个答案:

答案 0 :(得分:53)

Python中的列表被实现为指针 1 的数组。因此,创建列表时实际上发生了什么:

["perry", 1, 23.5, "s"]

实际上是在创建一个指针数组,如下所示:

[0xa3d25342, 0x635423fa, 0xff243546, 0x2545fade]

每个指针“指向”内存中的各个对象,因此字符串"perry"将存储在地址0xa3d25342中,数字1将存储在{{1}中}等

由于所有指针的大小相同,因此解释器可以实际上将元素大小的3倍加到0x635423fa的地址上,以获取存储在{{1 }}。


1 从以下位置获取更多详细信息:the horse's mouth (CPython source code on GitHub)

答案 1 :(得分:17)

您说a = [...]时,a实际上是指向PyObject的指针,其中包含指向PyObject s的指针的数组。

当您请求a[2]时,解释器首先跟随指针指向列表的PyObject,然后将2添加到列表中的数组的地址,然后返回该指针。如果您要求输入a[0]a[9999],也会发生同样的情况。

基本上,所有Python对象都是通过引用而不是值来访问的,甚至是2之类的整数文字。指针系统中只有一些技巧可以保持所有效率。而且指针的大小是已知的,因此可以方便地将它们存储在C样式的数组中。

答案 2 :(得分:6)

简短的回答:Python列表是数组。

长答案:计算机科学术语 list 通常是指单链接列表(如在函数编程中使用)或双链接列表(如在程序编程中使用)。这些数据结构支持O(1)插入到列表的开头(从功能上)或在不需要搜索的任何位置(从过程上)。 Python``列表''没有这些特征。相反,它支持在列表末尾附加(摊销)O(1)(例如C ++ std :: vector或Java ArrayList)。 Python列表实际上是CS术语中可调整大小的数组。

以下评论from the Python documentation解释了Python``列表''的一些性能特征:

  

也可以将列表用作队列,其中添加的第一个元素是检索到的第一个元素(“先进先出”);但是,列表对于此目的并不有效。尽管从列表末尾开始的添加和弹出很快速,但从列表开始进行插入或弹出很慢(因为所有其他元素都必须移动一个)。