[編集:完全に書き直されましたが、コメントはそのままにしてここに質問を残します。]
以下は、O(1)get / insert / delete、およびO(1)ランダム要素の選択による辞書ラッパーの実現です。
主なアイデアは、O(1)であるがrange(len(mapping))
、キーへの任意のマップが必要であるということです。これにより、を取得random.randrange(len(mapping))
してマッピングに渡すことができます。
マッピングが任意である可能性があるという事実を利用できることに気付くまで、これを実装することは非常に困難です。O(1)時間のハードバウンドを達成するための重要なアイデアは、次のとおりです。要素を削除するたびに、その要素を最高の任意ID要素と交換し、ポインターを更新します。
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])