SortedList по сравнению с SortedDictionary по сравнению с видом ()

Это - продолжение вопросов как этот.

Есть ли какие-либо инструкции для тонкой настройки производительности? Я не имею в виду усиления в большом-O, просто экономя некоторое линейное время.

Например, на каком количестве предварительная сортировка экономит также SortedList или SortedDictionary?

Скажите, что у меня есть класс человека с 3 свойствами к виду на, один из них является возрастом в годах. Действительно ли я должен объединить объекты в блок на возрасте сначала?

Должен я сначала вид на одном свойстве, затем использовать получающийся список/словарь для вида на двух свойствах и так далее?

Какая-либо другая оптимизация, которая приходит на ум?

22
задан Community 23 May 2017 в 12:31
поделиться

1 ответ

Вам придется думать о доходности Руби, как о вызове определяемой пользователем операции.

def twice
    yield
    yield
end

twice { puts "Hello" } 

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

partitions([1, 2, 3, 4].to_set) { |result| 
    # process result
}

Этот код вообще не создает список.

-121--4460409-

Проблема в том, что вы итерируете генераторы вместо списков в варианте выхода, а именно second G , который исчерпывается после одного цикла. Измените строку на эту и она работает:

firstG, secondG = f(first), list(f(second))

Или вы можете изменить свой цикл:

for e in ("(%s%s%s)" % (e1, op, e2) for e1 in f(first) for e2 in f(second)):
#                               new generator object every loop  ^^^^^^^^^

Неподходящая версия работает, потому что вы возвращаете списки, которые могут быть повторены, в отличие от генераторов. Также обратите внимание, что итерация выполняется над firstG только один раз, поэтому это не влияет.

Помните, что это:

r = [v for a in A for b in B]

эквивалентно:

r = []
for a in A:
  for b in B:
    r.append(v)

Что более ясно показывает повторяющийся цикл над B .

Другой пример:

def y():
  yield 1
  yield 2
  yield 3
def r():
  return [1, 2, 3]

vy = y()
for v in vy:
  print v
for v in vy:
  print v

print "---"

vr = r()
for v in vr:
  print v
for v in vr:
  print v
-121--5044895-

Ну, это легкая победа на SortedList. Для вставки предмета требуется двоичный поиск (O (log (n)), чтобы найти точку вставки, а затем List.Insert (O (n)), чтобы вставить предмет. Доминирует Insert (), для заполнения списка требуется O (n ^ 2). Если входные предметы уже отсортированы, команда Вставить сворачивается в O (1), но не влияет на поиск. Заполнение теперь равно O (nlog (n)). Ты не волнуешься, насколько велик О, сортировка в первую очередь всегда эффективнее. Предполагая, что вы можете позволить себе удвоить потребность в месте хранения.

SortedDictionary отличается, использует красно-черное дерево. Для нахождения точки вставки требуется O (log (n)). После этого может потребоваться повторное выравнивание дерева, которое также занимает O (log (n)). Таким образом, заполнение словаря занимает O (nlog (n)). Использование отсортированного ввода не изменяет усилия по поиску точки вставки или ребалансировки, это все еще O (nlog (n)). Теперь О имеет значение, но вставка отсортированных входных данных требует от дерева постоянного восстановления равновесия. Лучше работать, если входные данные являются случайными, отсортированные входные данные не нужны.

Таким образом, заполнение SortedList отсортированным вводом и заполнение SortedDictionary несортированным вводом имеет значение O (nlog (n)). Игнорируя затраты на предоставление отсортированных входных данных, Oh of SortedList меньше, чем Oh of SortedDictionary. Это деталь реализации из-за того, как List распределяет память. Он должен делать только O (log (n)) раз, красно-черное дерево должно распределять O (n) раз. Очень маленький O btw.

Примечательно, что ни один из них не сравнится с простым заполнением списка, а затем вызовет Sort (). Это также O (nlog (n)). На самом деле, если ввод уже случайно отсортирован, можно обойти вызов Sort (), это сворачивается до O (n). Анализ затрат теперь должен перейти к усилиям, необходимым для сортировки входных данных. Трудно обойти фундаментальную сложность Sort (), O (nlog (n)). Он может быть не виден, входные данные могут быть отсортированы, например, по SQL-запросу. Это займет больше времени.

точкой использования SortedList или SortedDictonary является сохранение сортировки коллекции после вставок.Если вы беспокоитесь только о том, чтобы заселить, но не мутировать, то вы не должны использовать эти коллекции.

57
ответ дан 29 November 2019 в 03:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: