Подтвердить что ты не робот

Эквивалентные классы и объединение/нахождение в функциональном языке

Для алгоритма автоматов мне нужна быстрая структура данных Union-Find на функциональном языке. Поскольку мне нужно официально доказать правильность структуры данных, я бы предпочел бы простую структуру.

Я пытаюсь вычислить классы эквивалентности элементов в наборе S w.r.t. отношение R ⊆ S × S. В конце я хочу получить некоторую функцию f: S → S, которая отображает любой элемент S в (канонический) представитель своего класса R -эквивалентности. Под "каноническим" я подразумеваю, что мне все равно, какой представитель он до тех пор, пока он одинаковый для всех элементов одного класса эквивалентности, т.е. Я хочу f x = f y ⟺ (x,y) ∈ R удерживать.

Какова была бы лучшая структура данных и алгоритм для этого в функциональном языке? Я должен добавить, что мне действительно нужен "нормальный" функциональный код, т.е. Не монады трансформации/состояния трансформатора.

EDIT: В то же время я придумал этот алгоритм:

m := empty map
for each s ∈ S do
  if m s = None then
    for each t in {t | (s,t) ∈ R}
      m := m[t ↦ s]

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

(мое отношение внутренне представлено как опция "S → (S Set)", следовательно, итерация по {t | (s, t) ∈ R} - это дешевая операция над этой структурой.)

4b9b3361

Ответ 1

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

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

Если вам не нужна соответствующая асимптотическая производительность, вы можете заменить массив произвольного доступа обычной структуры данных на постоянную ассоциативную карту, за счет дополнительного коэффициента производительности O (log N) и необходимости проверки его правильности.

Если вам нужна максимальная простота для целей проверки и не установлена ​​на любом из вышеперечисленных значений, вы можете использовать обновляемый массив и отказаться от оптимизации объединения по рангу. IIRC это дает O (log N) амортизацию наихудшего случая, но может фактически улучшить скорость выполнения (поскольку ранг больше не нужно хранить или управлять).