Временная сложность доступа к диктофону Python

Я пишу простую программу Python.

Моя программа, похоже, страдает от линейного доступа к словарям, его время выполнения растет экспоненциально, хотя алгоритм квадратичен.
Я использую словарь для запоминания значений. Это кажется узким местом.

Значения, которые я использую, являются кортежами точек. Каждая точка: (x, y), 0 <= x, y <= 50
Каждый ключ в словаре: Кортеж из 2-5 точек: ((x1, y1), (x2, y2), (x3, y3), (x4, y4))

Ключи читаются много раз чаще, чем они написаны.

Правильно ли, что python dicts страдает от линейного времени доступа с такими входами?

Насколько я знаю, у наборов есть гарантированное время логарифмического доступа.
Как я могу имитировать dicts с помощью наборов (или чего-то подобного) в Python?

edit В соответствии с запросом здесь (упрощенная версия) функции memoization:

def memoize(fun):
    memoized = {}
    def memo(*args):
        key = args
        if not key in memoized:
            memoized[key] = fun(*args)
        return memoized[key]
    return memo

Ответ 1

См. Сложность времени. Питон-питон - это хэш-карта, поэтому его худшим случаем является O (n), если хеш-функция плоха и приводит к множеству столкновений. Однако это очень редкий случай, когда каждый добавленный элемент имеет один и тот же хеш и поэтому добавляется в ту же цепочку, что для основной реализации Python было бы крайне маловероятным. Средняя временная сложность - это, конечно, O (1).

Лучший метод - проверить и взглянуть на хеши объектов, которые вы используете. CPython Dict использует int PyObject_Hash (PyObject * o), который является эквивалентом hash(o).

После быстрой проверки мне еще не удалось найти два кортежа для хэша с тем же значением, что указывает на то, что поиск равен O (1)

l = []
for x in range(0, 50):
    for y in range(0, 50):
        if hash((x,y)) in l:
            print "Fail: ", (x,y)
        l.append(hash((x,y)))
print "Test Finished"

CodePad (доступно в течение 24 часов)

Ответ 2

Вы не правы. dict доступ вряд ли будет вашей проблемой здесь. Это почти наверняка O (1), если у вас нет очень странных входов или очень плохой хэш-функции. Вставьте пример кода из вашего приложения для лучшего диагноза.

Ответ 3

Было бы проще сделать предложения, если бы вы предоставили пример кода и данных.

Доступ к словарю вряд ли будет проблемой, так как эта операция O (1) в среднем и O (N) амортизированный наихудший случай. Возможно, что встроенные функции хэширования столкнулись с вашими данными. Если у вас возникли проблемы с встроенной функцией хеширования, вы можете предоставить свои собственные.

Реализация словаря Python уменьшает среднюю сложность поиск слова в O (1) на требуя, чтобы ключевые объекты "хэш". Такая хэш-функция берет информацию в ключевом объекте и использует его для создания целого числа, называемое хэш-значением. Это значение хеша затем используется для определения "bucket" эта пара (ключ, значение) должна быть помещенным в.

Вы можете перезаписать метод __hash__ в своем классе, чтобы реализовать пользовательскую хеш-функцию следующим образом:

def __hash__(self):    
    return hash(str(self))

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

Ответ 4

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

Сколько кортежей вы помните? Рассматривали ли вы объем памяти? Возможно, вы тратите все свое время в памяти или памяти подкачки.

Ответ 5

Моя программа, похоже, страдает от линейного доступа к словарям, ее время выполнения растет экспоненциально, хотя алгоритм квадратичен.

Я использую словарь для запоминания значений. Это кажется узким местом.

Это свидетельствует об ошибке в методе memoization.

Ответ 6

Чтобы ответить на ваши конкретные вопросы:

Q1: "Я исправлю, что python dicts страдает от линейного времени доступа с такими входами?" "

A1: Если вы имеете в виду, что среднее время поиска равно O (N), где N - количество записей в dict, то весьма вероятно, что вы ошибаетесь. Если вы правы, сообщество Python очень хотело бы знать, при каких обстоятельствах вы правы, чтобы проблему можно было смягчить или, по крайней мере, предупредить. Ни "примерный" код, ни "упрощенный" код не являются полезными. Пожалуйста, покажите фактический код и данные, которые воспроизводят проблему. Код должен быть снабжен такими вещами, как количество элементов dict и количество обращений к типу для каждого P, где P - количество точек в ключе (2 <= P <= 5)

Q2: "" Насколько я знаю, у наборов есть гарантированное время логарифмического доступа. Как я могу имитировать dicts с помощью наборов (или чего-то подобного) в Python? ""

A2: Наборы имеют гарантированное логарифмическое время доступа в каком контексте? Такой гарантии для реализаций Python нет. В последних версиях CPython фактически используется реализация cut-down dict (только ключи, нет значений), поэтому ожидание - это среднее поведение O (1). Как вы можете имитировать dicts с наборами или что-то подобное на любом языке? Короткий ответ: с большой сложностью, если вы хотите любую функциональность за пределами dict.has_key(key).