我们都知道我们用的python一般都是Cpython,就是说底层是C语言写的,本文是对链接的学习
List对象的结构
typedef struct {
Pyobject_VAR_HEAD;
Pyobject **ob_item;
Py_ssize_t allocated;
}PyListObject;
我们可以看到里面的元素是二级指针,list名是一级指针,里面的元素也是指针,也就是说list中的元素其实是一个个的指针,指针指向真正的数据
这也就是为什么python的list可以添加任意类型的元素,另外allocated是ob_item预先分配的内存总容量
List的初始化,L = []会发生什么
arguments: size of the list = 0
returns: list object = []
PyListNew:
nbytes = size * size of global Python object = 0
allocate new list object
allocate list of pointers (ob_item) of size nbytes = 0
clear ob_item
set list's allocated var to 0 = 0 slots
return list object
list实际申请内存空间的大小和list实际存储元素所占空间的大小之间的关系要理解,ob_size和len(L)是一样的,而allocated(申请内存空间的大小)的大小是在内存中已经申请空间大小。通常情况下allocated的值要比ob_size的值要大,为了避免每次有新元素加入list时都要调用realloc进行内存分配
调用append
arguments: list object, new element
returns: 0 if OK, -1 if not
app1:
n = size of list
call list_resize() to resize the list to size n+1 = 0 + 1 = 1
list[n] = list[0] = new element
return 0
上面我们已经说了要避免经常调用realloc,这里也就是list_resize,要申请多余的空间防止多次调用list_resize函数
每次内存不够的增长模型在c++的vector中是每次容量是上次的2倍
但是这里的增长模型是:0, 4, 8, 16, 25, 35, 46, 58, 72, 88, …
(如何确立这种模型是需要进行大量数据分析来选择合适的模型)
一个指针数组,指向数值1
insert:
list_resize
arguments: list object, new size
return s: 0 if OK, -1 if not
list_resize:
new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6)
new_allocated += newsize = 3+1 = 4
resize ob_item(list of pointers) to size new_allocated
return 0
pop
list.pop会弹出最后一个元素,调用listpop(),list_resize在函数listpop内部被调用,因为弹出某个元素后可能ob_size小于allocated已经分配的内存空间的一半,则需要对申请的内存空间缩小
arguments: list object
returns: element popped
listpop:
if list empty:
return null
resize list with size
set list object size to xx
return last element
//pop的时间复杂度O(1)
复杂度为O(1):
remove
python list对象有一个方法可以移除一个指定的元素。调用listremove
arguments: list object, element to remove
returns none if OK, null if not
listremove:
loop through each list element
if correct element:
slice list between element's slot and element's slot + 1
return none
return null
切开list和删除元素,调用了list_as_slice()
arguments: list object, low offset, high offset
returns: 0 if OK
list_ass_slice:
copy integer 5 to recycle list to dereference it
shift elements from slot 2 to slot 1
resize list to 5 slots
return 0
//时间复杂度为O(n)
复杂度为O(n):