За счет Удобства использования теми, которые имеют программы для чтения с экрана, Вы могли просто на 90% использования страниц немаркированные, undenotable кнопки изображения. Поворачивайте изображения регулярно и используйте случайный генератор и случайную сортировку для разметки двух кнопок, которые говорят, что "Я хочу это" и "Я - бот". Разместите их сторона видом в другом порядке. На каждом этапе пользователь может сделать успехи torwards их цель, но бот, более вероятно, сделает ошибку (50% * количество шагов). Это похоже на получение на каждом этапе на более легком для пользователя и медленнее для ботов, кто должен предложить их ведущему устройству на Каждом шаге. Поместите цену, подтвердить кнопку, описание изделия в изображениях. Это сосет, но вероятно более успешный.
«Произвольный доступ O (1)» - чрезвычайно жесткое требование, которое в основном накладывает базовую хеш-таблицу - и я надеюсь, вы имеете в виду только случайное ЧТЕНИЕ, потому что я думаю, что это может быть доказано математически чем в общем случае невозможно иметь O (1) записи, а также O (N) упорядоченную итерацию.
Я не думаю, что вы найдете заранее упакованный контейнер, подходящий для ваших нужд, потому что они настолько экстремальны - - Доступ O (log N), конечно, будет иметь решающее значение в мире. Чтобы получить желаемое поведение при чтении и итерациях, вам нужно склеить две структуры данных, по сути, dict и кучу (или отсортированный список или дерево), и синхронизировать их. Хотя вы не указываете, я думаю, вы получите только амортизированное поведение того типа, который вам нужен - если только вы не мы действительно готовы платить любые потери производительности за вставки и удаления, что является буквальным следствием заявленных вами спецификаций, но действительно кажется довольно маловероятным в реальной жизни.
Для O (1) читать и амортизировать ] Упорядоченная итерация O (N), просто сохраните список всех ключей рядом с dict. Например:
class Crazy(object):
def __init__(self):
self.d = {}
self.L = []
self.sorted = True
def __getitem__(self, k):
return self.d[k]
def __setitem__(self, k, v):
if k not in self.d:
self.L.append(k)
self.sorted = False
self.d[k] = v
def __delitem__(self, k):
del self.d[k]
self.L.remove(k)
def __iter__(self):
if not self.sorted:
self.L.sort()
self.sorted = True
return iter(self.L)
Если вам не нравится «амортизированный порядок O (N)», вы можете удалить self.sorted и просто повторить self.L.sort ()
в __ setitem __
сам. Это, конечно, делает запись O (N log N) (в то время как у меня все еще была запись в O (1)). Любой из подходов жизнеспособен, и трудно думать о том, что один по своей сути превосходит другой. Если вы склонны делать кучу операций записи, а затем кучу итераций, то подход из приведенного выше кода будет лучшим; если это обычно одна запись, одна итерация, другая запись, еще одна итерация, тогда это просто промывка.
Кстати, это бесстыдное преимущество необычных (и замечательных ;-) характеристик производительности Python sort (также известных как «timsort»): среди них сортировка списка, который в основном отсортирован, но с несколькими дополнительными элементами, прикрепленными в конце, в основном O (N) (если прикрепленных элементов достаточно мало по сравнению с отсортированной частью префикса). Я слышал, что Java скоро набирает обороты, поскольку Джош Блок был настолько впечатлен техническим докладом о типе Python, что тут же начал писать код для JVM на своем ноутбуке. Большинство систем (включая, я полагаю, на сегодняшний день Jython и IronPython тоже) в основном имеют сортировку как операцию O (N log N), не используя преимущества «в основном упорядоченных» входных данных; "естественная сортировка слияний", которую Тим Питерс превратил в современный Python,
Вот моя собственная реализация:
import bisect
class KeyOrderedDict(object):
__slots__ = ['d', 'l']
def __init__(self, *args, **kwargs):
self.l = sorted(kwargs)
self.d = kwargs
def __setitem__(self, k, v):
if not k in self.d:
idx = bisect.bisect(self.l, k)
self.l.insert(idx, k)
self.d[k] = v
def __getitem__(self, k):
return self.d[k]
def __delitem__(self, k):
idx = bisect.bisect_left(self.l, k)
del self.l[idx]
del self.d[k]
def __iter__(self):
return iter(self.l)
def __contains__(self, k):
return k in self.d
Использование bisect сохраняет упорядоченность self.l, а вставка - O (n) (из-за вставки, но не убийца в моем случае, потому что я добавляю гораздо чаще, чем действительно вставляю, поэтому в обычном случае амортизируется O (1)). Доступ - O (1), итерация - O (n). Но, может быть, кто-то изобрел (на C) что-нибудь с более умной структурой?
Упорядоченное дерево обычно лучше для этого случая, но произвольный доступ будет log (n). Следует также учитывать затраты на установку и удаление ...
Я не уверен, какой Вы работаете с версией python, но, если вам нравится экспериментировать, Python 3.1 включает и официальную реализацию упорядоченных словарей: http://www.python.org/dev/peps/pep-0372/ http://docs.python.org/3.1/whatsnew/3.1.html#pep-372-ordered- dictionaries
вот такая штука: Мне было нужно нечто подобное. Однако обратите внимание, что эта конкретная реализация неизменяема, после создания экземпляра нет вставок: однако точная производительность не совсем соответствует тому, что вы просите. Поиск - O (журнал n), а полное сканирование - O (n). Это работает с использованием модуля bisect
над кортежем пар ключ / значение (кортеж). Даже если вы не можете использовать это точно, вы можете добиться успеха, адаптируя его к вашим потребностям.
import bisect
class dictuple(object):
"""
>>> h0 = dictuple()
>>> h1 = dictuple({"apples": 1, "bananas":2})
>>> h2 = dictuple({"bananas": 3, "mangoes": 5})
>>> h1+h2
('apples':1, 'bananas':3, 'mangoes':5)
>>> h1 > h2
False
>>> h1 > 6
False
>>> 'apples' in h1
True
>>> 'apples' in h2
False
>>> d1 = {}
>>> d1[h1] = "salad"
>>> d1[h1]
'salad'
>>> d1[h2]
Traceback (most recent call last):
...
KeyError: ('bananas':3, 'mangoes':5)
"""
def __new__(cls, *args, **kwargs):
initial = {}
args = [] if args is None else args
for arg in args:
initial.update(arg)
initial.update(kwargs)
instance = object.__new__(cls)
instance.__items = tuple(sorted(initial.items(),key=lambda i:i[0]))
return instance
def __init__(self,*args, **kwargs):
pass
def __find(self,key):
return bisect.bisect(self.__items, (key,))
def __getitem__(self, key):
ind = self.__find(key)
if self.__items[ind][0] == key:
return self.__items[ind][1]
raise KeyError(key)
def __repr__(self):
return "({0})".format(", ".join(
"{0}:{1}".format(repr(item[0]),repr(item[1]))
for item in self.__items))
def __contains__(self,key):
ind = self.__find(key)
return self.__items[ind][0] == key
def __cmp__(self,other):
return cmp(self.__class__.__name__, other.__class__.__name__
) or cmp(self.__items, other.__items)
def __eq__(self,other):
return self.__items == other.__items
def __format__(self,key):
pass
#def __ge__(self,key):
# pass
#def __getattribute__(self,key):
# pass
#def __gt__(self,key):
# pass
__seed = hash("dictuple")
def __hash__(self):
return dictuple.__seed^hash(self.__items)
def __iter__(self):
return self.iterkeys()
def __len__(self):
return len(self.__items)
#def __reduce__(self,key):
# pass
#def __reduce_ex__(self,key):
# pass
#def __sizeof__(self,key):
# pass
@classmethod
def fromkeys(cls,key,v=None):
cls(dict.fromkeys(key,v))
def get(self,key, default):
ind = self.__find(key)
return self.__items[ind][1] if self.__items[ind][0] == key else default
def has_key(self,key):
ind = self.__find(key)
return self.__items[ind][0] == key
def items(self):
return list(self.iteritems())
def iteritems(self):
return iter(self.__items)
def iterkeys(self):
return (i[0] for i in self.__items)
def itervalues(self):
return (i[1] for i in self.__items)
def keys(self):
return list(self.iterkeys())
def values(self):
return list(self.itervalues())
def __add__(self, other):
_sum = dict(self.__items)
_sum.update(other.__items)
return self.__class__(_sum)
if __name__ == "__main__":
import doctest
doctest.testmod()
Вы можете создать dict, который позволяет обход, сохранив пару (значение, next_key)
в каждой позиции.
Произвольный доступ:
my_dict[k][0] # for a key k
Обход:
k = start_key # stored somewhere
while k is not None: # next_key is None at the end of the list
v, k = my_dict[k]
yield v
Сохраните указатель на start
и end
, и у вас будет эффективное обновление для тех случаев, когда вам просто нужно добавить конец списка.
Вставка в середину, очевидно, O (n). Возможно, вы могли бы построить список пропуска поверх него, если вам нужно больше скорости.