根据https://www.ics.uci.edu/~pattis/ICS-33/lectures/complexitypython.txt,dict.clear()的时间复杂度为O(1)。据我所知,dict.clear()和dict = {}不同,因为dict.clear()会对同一个dict进行更改,而dict = {}会创建一个新的dict。现在,如果dict.clear()正在清除同一dict对象,那么它如何能够在O(1)内完成呢?
clear()
方法只是将内部字典结构分配给新的空值(可以在源代码中看到)。看似O(n)的部分是因为减少引用计数和其他与GC相关的事情。但这纯粹是CPython使用的GC方法(即引用计数)的函数;你可以想象不同的方法,不需要像这样显式地清理,或者清理会发生得更晚(甚至被摊销掉)。由于理想情况下clear()
方法的时间复杂度不应取决于底层GC方法,因此所有与GC相关的部分都被省略,使其变为“O(1)” 。在我看来,这主要是一个定义性的论点,但这至少是一些理由。我最初认为dict.clear
只是执行了一些引用减少操作,让垃圾收集器处理不干净的非O(1)工作,但是看了源代码(感谢提供链接的timgeb),似乎并不是这样的:
oldvalues = mp->ma_values;
if (oldvalues == empty_values)
return;
/* Empty the dict... */
dictkeys_incref(Py_EMPTY_KEYS);
mp->ma_keys = Py_EMPTY_KEYS;
mp->ma_values = empty_values;
mp->ma_used = 0;
mp->ma_version_tag = DICT_NEXT_VERSION();
/* ...then clear the keys and values */
if (oldvalues != NULL) {
n = oldkeys->dk_nentries;
for (i = 0; i < n; i++)
Py_CLEAR(oldvalues[i]);
NULL
。因此,看起来是O(n)
而不是O(1)
,因为它取决于值的数量。d = {}
时,这是O(1)
,但垃圾收集器必须在不再引用旧对象时删除它。除非Python突然退出,否则可能不正确。
PyDict_Clear
函数的实现可以在此处找到:https://github.com/python/cpython/blob/master/Objects/dictobject.c#L1636。 - timgebfor (i = 0; i < n; i++) Py_CLEAR(oldvalues[i]);
看起来并不像O(1)
…似乎我错了。 - Jean-François Fabre