append
向 List Object 任意位置插入数据,只要插入位置不是结尾,那么就需要将插入位置之后的元素后移,因此插入数据的时间复杂度为 O(n)。向数据插入数据有一个特例位置,向尾部追加 append 一个元素。
Python 的实现非常简单:
static int
app1(PyListObject *self, PyObject *v)
{
Py_ssize_t n = PyList_GET_SIZE(self);
// 省略了错误处理代码
if (list_resize(self, n+1) < 0)
return -1;
Py_INCREF(v);
PyList_SET_ITEM(self, n, v);
return 0;
}
只有两步:重置 List 空间;新增元素设置到尾部元素。非常直接。
pop
List 通过 pop 方法弹出元素。具体实现:
//Objects/listobject.c:1025
static PyObject *
list_pop_impl(PyListObject *self, Py_ssize_t index)
/*[clinic end generated code: output=6bd69dcb3f17eca8 input=b83675976f329e6f]*/
{
PyObject *v;
int status;
// 忽略一些无关代码
v = self->ob_item[index];
// 如果要弹出结尾元素,快捷处理
if (index == Py_SIZE(self) - 1) {
status = list_resize(self, Py_SIZE(self) - 1);
if (status >= 0)
return v; /* and v now owns the reference the list had */
else
return NULL;
}
// 如果位于 List 中间,则删除元素
Py_INCREF(v);
status = list_ass_slice(self, index, index+1, (PyObject *)NULL);
if (status < 0) {
Py_DECREF(v);
return NULL;
}
return v;
}
pop 元素根据弹出元素是否是尾部元素区别处理,如果是尾部元素,那么只是进行 resize 操作,弹出元素会被直接截断抛弃。实际上在这个过程中有可能根本不会发生真正的 resize,只是调整了 ob_size 的大小。
较为复杂的情况是弹出元素在数组中间或者头部,当目标元素弹出后,会在 List 中出现一个 “空缺”,其后的元素会被 “前移”,这与插入过程恰好相反。