Система непересекающихся множеств (, или ) — структура данных, которая позволяет администрировать множество элементов, разбитое на непересекающиеся подмножества. При этом каждому подмножеству назначается его представитель — элемент этого подмножества. Абстрактная структура данных определяется множеством трёх операций: .
Применяется для хранения компонент связности в графах, в частности, алгоритму Краскала необходима подобная структура данных для эффективной реализации.
Определение Пусть конечное множество, разбитое на непересекающиеся подмножества (классы) :
.
Каждому подмножеству назначается представитель . Соответствующая система непересекающихся множеств поддерживает следующие операции: : создаёт для элемента новое подмножество. Назначает этот же элемент представителем созданного подмножества. : объединяет оба подмножества, принадлежащие представителям и , и назначает представителем нового подмножества. : определяет для подмножество, к которому принадлежит элемент, и возвращает его представителя.
Алгоритмическая реализация Тривиальная реализация сохраняет принадлежность элементов из и представителей в индексном массиве. На практике же чаще используются множества деревьев. Это позволяет существенно сократить время, необходимое для операции . При этом представитель записывается в корень дерева, а остальные элементы класса в узлы под ним.
: вешает корень более низкого дерева под корень более высокого дерева. Если при этом становится потомком , оба узла меняются местами. : проходит путь от до корня дерева и возвращает его (корень в данном случае является представителем).
Эвристики Для ускорения операций и могут быть использованы эвристики , , и сжатие путей.
В эвристике во время операции корень меньшего дерева вешается под корень большего дерева. Благодаря этому подходу сохраняется балансировка дерева. Глубина каждого поддерева не может превысить величину . При использовании этой эвристики время операции в худшем случае увеличивается с до . Для эффективной реализации предлагается сохранять в корне количество узлов в дереве.
Эвристика аналогична , но использует высоту дерева вместо размера.
В эвристике используется тот факт, что можно не тратить дополнительные памяти на сохранение количества узлов в дереве: достаточно выбирать корень случайным образом — такое решение даёт на случайных запросах скорость, вполне сравнимую с другими реализациями. Тем не менее, если имеется много запросов вида «объединить большое множество с маленьким», данная эвристика улучшает матожидание (то есть среднее время работы) всего в два раза, поэтому использовать её без эвристики сжатия путей не рекомендуется.
Эвристика сжатия путей используется, чтобы ускорить операцию . При каждом новом поиске все элементы, находящиеся на пути от корня до искомого элемента, вешаются под корень дерева. В этом случае операция будет работать в среднем , где — функция, обратная функции Аккермана. Это позволяет значительно ускорить работу, так как для всех применяемых на практике значений принимает значение, меньшее 5.
Пример реализации
Реализация на C++: const int MAXN = 1000;
int p[MAXN], rank[MAXN];
void MakeSet(int x) { p[x] = x; rank[x] = 0; }
int Find(int x) { return ( x == p[x] ? x : p[x] = Find(p[x]) ); }
void Union(int x, int y) { if ( (x = Find(x)) == (y = Find(y)) ) return;
if ( rank[x] < rank[y] ) p[x] = y; else { p[y] = x; if ( rank[x] == rank[y] ) ++rank[x];
Реализация на Free Pascal: const MAX_N = 1000;
var Parent , Rank : array [ 1 .. MAX_N ] of LongInt;
procedure swap ( var x , y : LongInt ); var tmp : LongInt; begin tmp := x; x := y; y := tmp; end;
procedure MakeSet ( x : LongInt ) ; begin Parent[x] := x; Rank[x] := 0; end;
function Find ( x : LongInt ) : LongInt; begin if ( Parent[x] <> x ) then Parent[x] := Find ( Parent[x] ); Exit ( Parent[x] ); end;
procedure Union ( x , y : LongInt ); begin x := Find ( x ); y := Find ( y ); if ( x = y ) then exit(); if ( Rank[x] < Rank[y] ) then swap ( x , y );
Parent[y] := x; if ( Rank[x] = Rank[y] ) then inc ( Rank[x] ); end;
См. также Лес непересекающихся множеств
Литература Galler, Bernard A., and Michael J. Fisher. «An improved equivalence algorithm.» // Communications of the ACM, 7.5 (1964): 301—303. Tarjan, Robert E., and Jan Van Leeuwen. «Worst-case analysis of set union algorithms.» // Journal of the ACM 31.2 (1984): 245—281.
Ссылки Union-Find / Kevin Wayne, Pearson-Addison Wesley Chapter 22: Data Structures For Disjoint Sets / Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Rivest Визуализатор работы некоторых структур данных для непересекающихся множеств / ИТМО Реализация непересекающихся множеств в коллекции библиотек C++ Boost, 2006
Категория:Структуры данных