Как выбрать функциональную словарную структуру данных?

10

Я прочитал немного о следующих структурах данных:

  • Бэгвелла идеальные попытки хэша
  • Динамические хеш-таблицы Ларсона
  • Красно-черные деревья
  • Патриция деревья

... и я уверен, что есть много других. Я очень мало видел в том, для чего каждый из них лучше подходит, или почему я бы выбрал одно из другого. Итак, вот несколько вопросов по этим направлениям:

  1. Какие функциональные словарные структуры данных важно знать?
  2. Каковы плюсы и минусы этих подходов?
  3. Когда имеет смысл использовать более императивную структуру данных?

Числа 2 и 3 являются более важными, хотя. :-)

Джейсон
источник
Связанный: Что нового в чисто функциональных структурах данных со времен Окасаки? (Этот вопрос не ограничивается словарями.)
Tsuyoshi Ito
Этот вопрос (кроме пункта с номером 3) выглядит как [большой список].
Каве
2
было бы полезно узнать, отвечает ли приведенный выше вопрос вашим проблемам, и если нет, то почему?
Суреш Венкат
@Suresh - Это ответы № 1, но 2 и 3 были более важными. Я в основном ищу общий обзор, чтобы определить, какие из них заслуживают более глубокого изучения.
Джейсон
2
Хорошо. так что, возможно, стоит отредактировать вопрос.
Суреш Венкат

Ответы:

16

Я не могу ответить № 2, не потерявшись (слишком много измерений, по которым вы можете сравнить эти структуры), но для № 3 ответ довольно прост.

Используйте императивную структуру данных, если: (а) псевдонимы абсолютно отсутствуют или (б) вам действительно нужно использовать псевдонимы для эффективной трансляции.

Если в вашей структуре данных нет псевдонимов, вы не пользуетесь тем, что функциональные структуры данных являются постоянными. Так что нет причин платить за их стоимость. Есть два предостережения к этому совету. Во-первых, вы можете предпочесть простоту реализации функциональной структуры данных: реализация удаления для функционального красно-черного дерева заставит вас ругаться, но реализация удаления в императивном красно-черном дереве с родительскими указателями оставит вас в ожидании самоубийства. Во-вторых, назначение может быть более дорогим, чем вы ожидаете в gc'd языке, поскольку записи могут вывести структуры данных из молодого поколения. У нас действительно нет хорошей теории эффектов кеша и gc, поэтому у вас нет выбора, кроме как сделать бенчмаркинг.

Во-вторых, если вам нужен канал вещания, то общая структура данных - отличный способ сделать это. Благодаря постоянному обновлению вы можете произвольно сказать многим другим людям, что значение изменилось. (Вот почему union-find представляет собой такую ​​замечательную структуру данных.) С чисто функциональной настройкой вам нужно либо изменить всех этих людей, либо дать им абстрактные указатели в состояние, которое вы кодируете вручную (что является своего рода тупым вещь которую нужно сделать).

Если вы не хотите рассуждать о псевдонимах и владении объектами или если вам нужно несколько версий одной и той же структуры данных (скажем, вам нужна как новая, так и старая версия), просто используйте функциональную структуру данных.

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

Нил Кришнасвами
источник
2
что такое псевдоним в этом контексте?
Суреш Венкат
6
Псевдоним - это когда у вас есть несколько ссылок на один и тот же фрагмент данных. Если эти данные являются изменяемыми, то при рассуждении о программе, которая их использует, необходимо явно учесть все другие подпрограммы, которые могут получить к ним доступ и изменить их. Если этот фрагмент данных является неизменным, то вы можете локально рассуждать о программе, которая его использует, игнорируя псевдонимы, поскольку вы не знаете, что никто, кто может получить доступ к данным, не может изменить их.
Нил Кришнасвами
«но реализация удаления в императивном красно-черном дереве с родительскими указателями заставит вас задуматься о самоубийстве» Посмотрите на лево-склонные красно-черные деревья Седжвика. Общий случай удаления сводится к delete-min стандартным трюком, а сама delete-min очень проста для деревьев LLRB. Не нужны родительские указатели.
Per Vognsen
1
«Это, как правило, довольно ужасно, полно ошибок и может потерять преимущество в производительности императивного алгоритма». Статья Нормана Рэмси об использовании застежек-молний для управляющих потоковых диаграмм в оптимизирующем компиляторе дает пример убедительного компромисса. У вас фактически есть локальная куча для поддержки простого и эффективного переподключения ссылок между базовыми блоками в CFG, но манипулирование содержимым базовых блоков является функциональным (или полуфункциональным, в зависимости от вашего философского взгляда на молнии).
Per Vognsen
1

Какие функциональные словарные структуры данных важно знать?

Сбалансированные по высоте бинарные деревья и их попытки являются хорошим всесторонним компромиссом. Также:

  • Патриция деревья.
  • Хэш пытается

Каковы плюсы и минусы этих подходов?

Бинарные деревья с сбалансированной высотой и их попытки являются хорошим универсальным компромиссом для атомарных ключей. Попытки одинаковы для ключей, которые являются последовательностями, например строковые ключи.

Деревья Патриции могут быть в несколько раз быстрее, но разрешать только целочисленные ключи.

Попытки хеширования могут быть в несколько раз быстрее, чем сбалансированные двоичные деревья, особенно если хеширование дешевле, чем сравнение, и полиморфизм имеет накладные расходы (например, строки в .NET), а запись указателей в кучу выполняется быстро (например, виртуальные машины, такие как JVM и CLR, которые были оптимизирован для императивных языков, а не функциональных языков). Попытки хэширования также позволяют использовать мутацию для оптимизации.

Красно-черные деревья менее важны, потому что они не имеют каких-либо существенных преимуществ по сравнению с деревьями с сбалансированной высотой, но имеют существенный недостаток, заключающийся в том, что они не допускают эффективного объединения, пересечения и различия.

Точно так же пальчики не намного лучше на практике.

Когда имеет смысл использовать более императивную структуру данных?

Когда ваш словарь заполняется один раз, а затем используется только для поиска, то есть заморожен.

Когда вам нужна производительность (приличная хеш-таблица, такая как .NET, Dictionaryкак правило, в 10-40 раз быстрее любого обычного чисто функционального словаря).

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

Джон Харроп
источник