在Python中合并两个列表的运行时

时间:2015-03-22 17:54:46

标签: python list time-complexity

假设我们有两个列表A = [a1, a2, ..., an](n个元素)和B = [b1, b2, ..., bm](m个元素),我们在Python中使用“+”将两个列表合并为一个,所以

C = A + B;

我的问题是这个操作的运行时是什么?我的第一个猜测是O(n+m),不确定Python是否比那更聪明。

3 个答案:

答案 0 :(得分:6)

当您使用A + B连接两个列表时,您将在内存中创建一个全新的列表。这意味着您的猜测是正确的:复杂性为O(n + m)(其中nm是列表的长度),因为Python必须依次遍历两个列表以构建新列表。

您可以在source code for Python lists

list_concat函数中看到这种情况
static PyObject *
list_concat(PyListObject *a, PyObject *bb)
{
/* ...code snipped... */
    src = a->ob_item;
    dest = np->ob_item;
    for (i = 0; i < Py_SIZE(a); i++) {     /* walking list a */
        PyObject *v = src[i];
        Py_INCREF(v);
        dest[i] = v;
    }
    src = b->ob_item;
    dest = np->ob_item + Py_SIZE(a);
    for (i = 0; i < Py_SIZE(b); i++) {     /* walking list b */
        PyObject *v = src[i];
        Py_INCREF(v);
        dest[i] = v;
    }
/* ...code snipped... */

如果你不需要内存中的新列表,那么利用列表是可变的这一事实通常是个好主意(这就是Python 智能的地方)。在复杂性方面使用A.extend(B) O(m)意味着您可以避免复制列表a的开销。

在Python维基上列出了各种列表操作的复杂性here

答案 1 :(得分:2)

  

我的第一个猜测是O(n+m),不确定Python是否比那更聪明。

在返回副本时,没有什么可以比这更聪明。虽然AB是不可变的序列,如字符串; CPython仍然使用完整副本而不是别名相同的内存(它简化了对这些字符串的垃圾收集的实现)。

在某些特定情况下,操作可能是O(1),具体取决于您要对结果执行的操作,例如,itertools.chain(A, B)允许迭代所有项目(它不会复制,更改在A中,B影响已产生的项目)。或者如果您需要随机访问;您可以使用Sequence子类(例如WeightedPopulation来模拟它,但在一般情况下,副本和O(n+m)运行时是不可避免的。

答案 2 :(得分:0)

复制列表为O(n)(n为元素数),扩展名为O(k)(n为第二个列表中的元素数)。根据这两个事实,我认为它不能小于O(n+k),因为这是一个复制和扩展操作,至少你需要复制两个列表的所有元素。

来源:Python TimeComplexity