[редактировать:. Полностью переписан, но сохраняющий вопрос здесь с комментариями интактных]
Ниже реализация словаря обертку с O (1) получить/вставка/удаление, и O (1) сбор случайного элемента.
Основная идея состоит в том, что мы хотим иметь O (1), но произвольное отображение от range(len(mapping))
к ключам. Это позволит нам получить random.randrange(len(mapping))
и передать его через картографию.
Это очень сложно реализовать, пока вы не поймете, что мы можем воспользоваться тем, что отображение может быть произвольным. Ключевой идеей для достижения жесткой границы времени O (1) является следующее: всякий раз, когда вы удаляете элемент, вы меняете его с наивысшим элементом произвольного идентификатора и обновляете любые указатели.
class RandomChoiceDict(object):
def __init__(self):
self.mapping = {} # wraps a dictionary
# e.g. {'a':'Alice', 'b':'Bob', 'c':'Carrie'}
# the arbitrary mapping mentioned above
self.idToKey = {} # e.g. {0:'a', 1:'c' 2:'b'},
# or {0:'b', 1:'a' 2:'c'}, etc.
self.keyToId = {} # needed to help delete elements
Получить, установить и удалить:
def __getitem__(self, key): # O(1)
return self.mapping[key]
def __setitem__(self, key, value): # O(1)
if key in self.mapping:
self.mapping[key] = value
else: # new item
newId = len(self.mapping)
self.mapping[key] = value
# add it to the arbitrary bijection
self.idToKey[newId] = key
self.keyToId[key] = newId
def __delitem__(self, key): # O(1)
del self.mapping[key] # O(1) average case
# see http://wiki.python.org/moin/TimeComplexity
emptyId = self.keyToId[key]
largestId = len(self.mapping) # about to be deleted
largestIdKey = self.idToKey[largestId] # going to store this in empty Id
# swap deleted element with highest-id element in arbitrary map:
self.idToKey[emptyId] = largestIdKey
self.keyToId[largestIdKey] = emptyId
del self.keyToId[key]
del self.idToKey[largestId]
Сбор случайный (ключ, элемент):
def randomItem(self): # O(1)
r = random.randrange(len(self.mapping))
k = self.idToKey[r]
return (k, self.mapping[k])
Вот идея: сохраните еще один 'dict' формы' {i: key} ', где' i' является счетчиком. Затем, чтобы выполнить случайный поиск, вызовите 'randint' в этом другом словаре. Исправьте меня, если я ошибаюсь, но это звучит как O (1). –
Ну, это не очевидно, как делать вставку и удаление, из того, что вы сказали. Однако это действительно работает. Следите за максимальным значением счетчика, назовите его n. Для вставок мы сначала пробуем 2 (или 5 или любое постоянное число) случайных значений между 1 и n. Если они были сделаны, используйте n и увеличьте значение максимального счетчика. В противном случае вставьте на пустой. Ухоженная! – WuTheFWasThat
Мне любопытно, как использовать эту структуру данных. Какой прецедент? – Daenyth