它是链表还是数组?我四处搜寻,只发现人们在猜测。我的C语言知识还不够好,不能看源代码。
当前回答
实际上,C代码非常简单。扩展一个宏并删除一些不相关的注释,基本结构在listobject.h中,它将列表定义为:
typedef struct {
PyObject_HEAD
Py_ssize_t ob_size;
/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */
PyObject **ob_item;
/* ob_item contains space for 'allocated' elements. The number
* currently in use is ob_size.
* Invariants:
* 0 <= ob_size <= allocated
* len(list) == ob_size
* ob_item == NULL implies ob_size == allocated == 0
*/
Py_ssize_t allocated;
} PyListObject;
PyObject_HEAD包含引用计数和类型标识符。这是一个过度分配的向量/数组。当数组满时,调整数组大小的代码在listobject.c中。它实际上并没有使数组加倍,而是通过分配来增长
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6);
new_allocated += newsize;
到每次的容量,其中newsize是请求的大小(不一定分配+ 1,因为您可以扩展任意数量的元素,而不是逐个添加它们)。
参见Python常见问题解答。
其他回答
这取决于实现,但IIRC:
CPython使用指针数组 Jython使用数组列表 IronPython显然也使用数组。您可以浏览源代码来找到答案。
因此它们都有O(1)个随机访问。
在CPython中,列表是指针的数组。Python的其他实现可以选择以不同的方式存储它们。
我发现这篇文章对于理解如何使用python代码实现列表非常有帮助。
class OhMyList:
def __init__(self):
self.length = 0
self.capacity = 8
self.array = (self.capacity * ctypes.py_object)()
def append(self, item):
if self.length == self.capacity:
self._resize(self.capacity*2)
self.array[self.length] = item
self.length += 1
def _resize(self, new_cap):
new_arr = (new_cap * ctypes.py_object)()
for idx in range(self.length):
new_arr[idx] = self.array[idx]
self.array = new_arr
self.capacity = new_cap
def __len__(self):
return self.length
def __getitem__(self, idx):
return self.array[idx]
在CPython中,list是作为动态数组实现的,因此当我们追加时,不仅添加了一个宏,而且分配了更多的空间,这样每次都不应该添加新的空间。
正如上面其他人所述,列表(当相当大时)是通过分配固定数量的空间来实现的,如果该空间应该被填满,则分配更大数量的空间并复制元素。
To understand why the method is O(1) amortized, without loss of generality, assume we have inserted a = 2^n elements, and we now have to double our table to 2^(n+1) size. That means we're currently doing 2^(n+1) operations. Last copy, we did 2^n operations. Before that we did 2^(n-1)... all the way down to 8,4,2,1. Now, if we add these up, we get 1 + 2 + 4 + 8 + ... + 2^(n+1) = 2^(n+2) - 1 < 4*2^n = O(2^n) = O(a) total insertions (i.e. O(1) amortized time). Also, it should be noted that if the table allows deletions the table shrinking has to be done at a different factor (e.g 3x)
推荐文章
- 滚动或滑动窗口迭代器?
- python的方法找到最大值和它的索引在一个列表?
- 如何读取文件的前N行?
- 如何删除matplotlib中的顶部和右侧轴?
- 解析.py文件,读取AST,修改它,然后写回修改后的源代码
- c++中有最大数组长度限制吗?
- Visual Studio Code:如何调试Python脚本的参数
- 如何克隆或复制一个列表在kotlin
- 使用元组/列表等等。从输入vs直接引用类型如list/tuple/etc
- 结合conda环境。Yml和PIP requirements.txt
- 将命名元组转换为字典
- 如何使x轴和y轴的刻度相等呢?
- Numpy在这里函数多个条件
- 在Python中,使用argparse只允许正整数
- 如何排序mongodb与pymongo