Внутренние элементы списка Python, доступ и время изменения размера - PullRequest
30 голосов
/ 09 мая 2011

Является ли Python's [] списком или массивом?
Является ли время доступа индекса O (1) как массива или O (n) как списка?
Является ли добавление / изменение размера O (1) как списка или O (n) как массива, или это гибрид, который может управлять O (1) для доступа и изменения размера?

Я прочитайте здесь , что доступ к массиву в Python очень медленный. Однако, когда я написал запомненную версию рекурсивной процедуры Фибоначчи, используя как словарь (словарь Python должен быть очень быстрым), так и список, у них было одинаковое время. Почему это?

Имеет ли кортеж Python более быстрое время доступа, чем список питонов?

Ответы [ 4 ]

40 голосов
/ 09 мая 2011

Python [] реализован в виде массива , а не связанного списка.Хотя изменение размера равно O (n), к нему добавляется амортизированный O (1) , поскольку изменение размера происходит очень редко.Если вы не знакомы с тем, как это работает, прочитайте эту запись в Википедии о динамических массивах .Список Python не увеличивается в 2 раза каждый раз, он немного сложнее, но расширения по-прежнему предназначены для добавления амортизируемого O (1).

Вставка в середине, однако,всегда неэффективно O (n), потому что n элементов, возможно, придется перемещать.

Кортежи не быстрее списков - это просто неизменяемые списки под капотом (*).

Относительно вашего словарного теста: в зависимости от вашей конкретной реализации, кэширование в списке будетбыстрее чем с диктом.Тем не менее, команды Python высоко оптимизированы, и особенно для небольших количеств ключей будут работать отлично.


(*) Вот функция C "get item" списка в Python 2.6:

PyObject *
PyList_GetItem(PyObject *op, Py_ssize_t i)
{
    if (!PyList_Check(op)) {
        PyErr_BadInternalCall();
        return NULL;
    }
    if (i < 0 || i >= Py_SIZE(op)) {
        if (indexerr == NULL)
            indexerr = PyString_FromString(
                "list index out of range");
        PyErr_SetObject(PyExc_IndexError, indexerr);
        return NULL;
    }
    return ((PyListObject *)op) -> ob_item[i];
}

И это кортеж:

PyObject *
PyTuple_GetItem(register PyObject *op, register Py_ssize_t i)
{
    if (!PyTuple_Check(op)) {
        PyErr_BadInternalCall();
        return NULL;
    }
    if (i < 0 || i >= Py_SIZE(op)) {
        PyErr_SetString(PyExc_IndexError, "tuple index out of range");
        return NULL;
    }
    return ((PyTupleObject *)op) -> ob_item[i];
}

Как видите, они почти одинаковы.В конце, после некоторой проверки типов и границ, это простой доступ указателя с индексом.

[Ссылка: Документация Python по сложности времени для операций с типами данных ]

10 голосов
/ 09 мая 2011

Здесь есть большой список здесь , описывающий временную сложность типов данных Python.В вашем случае поиск предмета должен быть O (1) раз.

2 голосов
/ 09 мая 2011

Список Python сопоставим с ArrayList Java. время доступа для получения элемента из списка и кортежа должно O(1). В статье Norvig отмечается, что список Python сравним с Vector в Java или Adjustable Array в Lisp, и вам действительно нужно больше места, но время доступа составляет O(1).

0 голосов
/ 09 мая 2011

Кортежи на быстрее списков.Я не знаю основную реализацию.В какой-то момент я прочитал это в «Погружении в Python» :) Соответствующий отрывок:

«Кортежи работают быстрее списков. Если вы определяете постоянный набор значений и все, что вы когда-либо будете делатьс итерацией по нему, используйте кортеж вместо списка. "

...