Python list.clear复杂性

时间:2017-10-28 01:44:39

标签: python python-3.x time-complexity

Python 3方法list.clear()的复杂性是什么?

  • 此处未给出: https://wiki.python.org/moin/TimeComplexity

  • documentation中,它被认为与del a[:]等效,但我不知道这个函数本身的复杂性。是 它是O(n)还是O(1)

  • 我看了listobject.c。发现了这个。

    int
    PyList_ClearFreeList(void)
    {
        PyListObject *op;
        int ret = numfree;
        while (numfree) {
            op = free_list[--numfree];
            assert(PyList_CheckExact(op));
            PyObject_GC_Del(op);
        }
        return ret;
    }
    

    这似乎是O(n),但我不确定这是否是正确的代码。

我正在开发一个具有性能需求的程序,其中列表被反复填充和清空,我正在尝试找到清空它的最佳方法(因为只有一种方法可以填充它) 。

如果此功能为O(n),我只会每次创建一个新列表,这有自己的成本,但我不知道更好方式。

我想到的另一个问题是Python有一个垃圾收集器,所以如果我不释放这些对象(每次都创建新列表,通过重新分配变量名来让另一个无人看管),Python会删除背景(我不确定这些信息),所以我不会使用上述任何方法获得速度,因为结果是相同的。

感谢任何知识。感谢。

2 个答案:

答案 0 :(得分:2)

您找到的函数与 Python 中的 list.clear() 无关。您需要的是 _list_clear(PyListObject *a),它可以在 here 中找到。

因此,如果您查看该方法的实现,则如下所示:

...
static int
_list_clear(PyListObject *a)
{
    Py_ssize_t i;
    PyObject **item = a->ob_item;
    if (item != NULL) {
        /* Because XDECREF can recursively invoke operations on
           this list, we make it empty first. */
        i = Py_SIZE(a);
        Py_SIZE(a) = 0;
        a->ob_item = NULL;
        a->allocated = 0;
        while (--i >= 0) {
            Py_XDECREF(item[i]);
        }
        PyMem_FREE(item);
    }
    /* Never fails; the return value can be ignored.
       Note that there is no guarantee that the list is actually empty
       at this point, because XDECREF may have populated it again! */
    return 0;
}
...

然而,最重要的一行是检索列表大小的一行:

i = Py_SIZE(a);

还有那些,你要删除一个元素:

...
    while (--i >= 0) {
        Py_XDECREF(item[i]);
    }
...

由于 Py_XDECREF 的性能不依赖于列表的大小,我们可以将其视为常数或 O(1)。由于 Py_XDECREF 被称为列表时间的大小,因此整体时间复杂度是线性的,因此 _list_clear 的时间复杂度为 O(n)。

正如@superbrain 所指出的,对于某些元素,Py_XDECREF 可能会变得非常“重”(由于可能的递归调用),尽管它与输入大小没有直接关系,但我们可以通过引入参数 e - 减少元素引用计数的总成本。在这种解释中,总时间复杂度为 O(n+e)。

答案 1 :(得分:0)

过早优化......和XY problems ...

也许最好的方法更务实?编写程序,看看是否需要额外的性能。然后测量您列出的不同选项,并选择更快的选项。

O()符号见解可能会或可能不会转化为性能,尤其是在不同级别执行不同操作的python中。

关于您的具体问题:
创建新列表并让垃圾收集器完成其工作可以说是更清晰 但是,列表是可自动调整大小的对象,它们在分摊的时间内运行。如果您的计划对性能至关重要,您可能需要考虑更专业的结构,例如arraynumpy.arrayc structs