<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>http://digida.mgpu.ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=31.186.66.0%2F24</id>
	<title>Поле цифровой дидактики - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="http://digida.mgpu.ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=31.186.66.0%2F24"/>
	<link rel="alternate" type="text/html" href="http://digida.mgpu.ru/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/31.186.66.0/24"/>
	<updated>2026-09-28T18:08:52Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.46.0</generator>
	<entry>
		<id>http://digida.mgpu.ru/index.php?title=%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D0%BD%D0%B5%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D0%BA%D0%B0%D1%8E%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2&amp;diff=4508</id>
		<title>Система непересекающихся множеств</title>
		<link rel="alternate" type="text/html" href="http://digida.mgpu.ru/index.php?title=%D0%A1%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0_%D0%BD%D0%B5%D0%BF%D0%B5%D1%80%D0%B5%D1%81%D0%B5%D0%BA%D0%B0%D1%8E%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2&amp;diff=4508"/>
		<updated>2020-12-22T19:08:24Z</updated>

		<summary type="html">&lt;p&gt;31.186.66.108: /* Определение */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Система непересекающихся множеств&#039;&#039;&#039; ({{lang-en|disjoint-set}}, или {{lang-en2|union–find}} {{lang-en2|data structure}}) — [[структура данных]], которая позволяет администрировать множество элементов, разбитое на непересекающиеся подмножества. При этом каждому подмножеству назначается его представитель — элемент этого подмножества. Абстрактная структура данных определяется множеством трёх операций: &amp;lt;math&amp;gt;\{\mathrm{Union}, \mathrm{Find}, \mathrm{MakeSet}\}&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Применяется для хранения [[Компонента связности графа|компонент связности]] в [[Граф (математика)|графах]], в частности, [[Алгоритм Краскала|алгоритму Краскала]] необходима подобная структура данных для эффективной реализации.&lt;br /&gt;
&lt;br /&gt;
== Определение ==&lt;br /&gt;
Пусть &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; конечное множество, разбитое на непересекающиеся подмножества ([[Класс (математика)|классы]]) &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
: &amp;lt;math&amp;gt;S = X_0 \cup X_1 \cup X_2 \cup \ldots \cup X_k: X_i \cap X_j = \varnothing \quad\forall i, j \in \lbrace 0, 1, \ldots, k \rbrace, i \neq j&amp;lt;/math&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Каждому подмножеству &amp;lt;math&amp;gt;X_i&amp;lt;/math&amp;gt; назначается представитель &amp;lt;math&amp;gt;r_i \in X_i&amp;lt;/math&amp;gt;.&lt;br /&gt;
Соответствующая система непересекающихся множеств поддерживает следующие операции:&lt;br /&gt;
* &amp;lt;math&amp;gt;\mathrm{MakeSet}(x)&amp;lt;/math&amp;gt;: создаёт для элемента &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; новое подмножество. Назначает этот же элемент представителем созданного подмножества.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mathrm{Union}(r, s)&amp;lt;/math&amp;gt;: объединяет оба подмножества, принадлежащие представителям &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; и &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt;, и назначает &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; представителем нового подмножества.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mathrm{Find}(x)&amp;lt;/math&amp;gt;: определяет для &amp;lt;math&amp;gt;x \in S&amp;lt;/math&amp;gt; подмножество, к которому принадлежит элемент, и возвращает его представителя.&lt;br /&gt;
&lt;br /&gt;
== Алгоритмическая реализация ==&lt;br /&gt;
Тривиальная реализация сохраняет принадлежность элементов из &amp;lt;math&amp;gt;S&amp;lt;/math&amp;gt; и представителей &amp;lt;math&amp;gt;r_i&amp;lt;/math&amp;gt; в [[Индексный массив|индексном массиве]]. На практике же чаще используются множества [[Дерево (теория графов)|деревьев]]. Это позволяет существенно сократить время, необходимое для операции {{math|Find}}. При этом представитель записывается в корень дерева, а остальные элементы класса в узлы под ним.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;math&amp;gt;\mathrm{Union}(r, s)&amp;lt;/math&amp;gt;: вешает корень более низкого дерева под корень более высокого дерева. Если при этом &amp;lt;math&amp;gt;r&amp;lt;/math&amp;gt; становится потомком &amp;lt;math&amp;gt;s&amp;lt;/math&amp;gt;, оба узла меняются местами.&lt;br /&gt;
* &amp;lt;math&amp;gt;\mathrm{Find}(x)&amp;lt;/math&amp;gt;: проходит путь от &amp;lt;math&amp;gt;x&amp;lt;/math&amp;gt; до корня дерева и возвращает его (корень в данном случае является представителем).&lt;br /&gt;
&lt;br /&gt;
== Эвристики ==&lt;br /&gt;
Для ускорения операций {{math|Union}} и {{math|Find}} могут быть использованы эвристики {{math|Union-By-Size}}, {{math|Union-By-Height}}, {{math|Random-Union}} и сжатие путей.&lt;br /&gt;
&lt;br /&gt;
В эвристике {{math|Union-By-Size}} во время операции &amp;lt;math&amp;gt;\mathrm{Union}(r, s)&amp;lt;/math&amp;gt; корень меньшего дерева вешается под корень большего дерева. Благодаря этому подходу сохраняется балансировка дерева. Глубина каждого поддерева &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; не может превысить величину &amp;lt;math&amp;gt;\log \left|T\right|&amp;lt;/math&amp;gt;. При использовании этой эвристики время операции {{math|Find}} в худшем случае увеличивается с &amp;lt;math&amp;gt;O(\log n)&amp;lt;/math&amp;gt; до &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt;. Для эффективной реализации предлагается сохранять в корне количество узлов в дереве.&lt;br /&gt;
&lt;br /&gt;
Эвристика {{math|Union-By-Height}} аналогична {{math|Union-By-Size}}, но использует высоту дерева вместо размера.&lt;br /&gt;
&lt;br /&gt;
В эвристике {{math|Random-Union}} используется тот факт, что можно не тратить дополнительные &amp;lt;math&amp;gt;O(n)&amp;lt;/math&amp;gt; памяти на сохранение количества узлов в дереве: достаточно выбирать корень случайным образом — такое решение даёт на случайных запросах скорость, вполне сравнимую с другими реализациями. Тем не менее, если имеется много запросов вида «объединить большое множество с маленьким», данная эвристика улучшает [[матожидание]] (то есть среднее время работы) всего в два раза, поэтому использовать её без эвристики сжатия путей не рекомендуется.&lt;br /&gt;
&lt;br /&gt;
Эвристика сжатия путей используется, чтобы ускорить операцию &amp;lt;math&amp;gt;\mathrm{Find}(x)&amp;lt;/math&amp;gt;. При каждом новом поиске все элементы, находящиеся на пути от корня до искомого элемента, вешаются под корень дерева. В этом случае операция {{math|Find}} будет работать в среднем &amp;lt;math&amp;gt;\alpha(n)&amp;lt;/math&amp;gt;, где &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; — функция, обратная [[Функция Аккермана|функции Аккермана]]. Это позволяет значительно ускорить работу, так как &amp;lt;math&amp;gt;\alpha&amp;lt;/math&amp;gt; для всех применяемых на практике значений принимает значение, меньшее 5.&lt;br /&gt;
&lt;br /&gt;
== Пример реализации ==&lt;br /&gt;
&lt;br /&gt;
Реализация на C++:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
const int MAXN = 1000;&lt;br /&gt;
&lt;br /&gt;
int p[MAXN], rank[MAXN];&lt;br /&gt;
&lt;br /&gt;
void MakeSet(int x) &lt;br /&gt;
{&lt;br /&gt;
    p[x] = x;&lt;br /&gt;
    rank[x] = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int Find(int x) &lt;br /&gt;
{&lt;br /&gt;
    return ( x == p[x] ? x : p[x] = Find(p[x]) );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void Union(int x, int y) &lt;br /&gt;
{&lt;br /&gt;
    if ( (x = Find(x)) == (y = Find(y)) )&lt;br /&gt;
        return;&lt;br /&gt;
	&lt;br /&gt;
    if ( rank[x] &amp;lt;  rank[y] )&lt;br /&gt;
        p[x] = y;&lt;br /&gt;
    else {&lt;br /&gt;
        p[y] = x;&lt;br /&gt;
        if ( rank[x] == rank[y] )&lt;br /&gt;
            ++rank[x];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Реализация на Free Pascal:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot; line=&amp;quot;1&amp;quot;&amp;gt;&lt;br /&gt;
const MAX_N = 1000;&lt;br /&gt;
&lt;br /&gt;
var Parent , Rank : array [ 1 .. MAX_N ] of LongInt;&lt;br /&gt;
&lt;br /&gt;
procedure swap ( var x , y : LongInt );&lt;br /&gt;
  var tmp : LongInt;&lt;br /&gt;
begin&lt;br /&gt;
  tmp := x; &lt;br /&gt;
  x := y; &lt;br /&gt;
  y := tmp;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure MakeSet ( x : LongInt ) ;&lt;br /&gt;
begin&lt;br /&gt;
  Parent[x] := x;&lt;br /&gt;
  Rank[x] := 0;&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
function Find ( x : LongInt ) : LongInt;&lt;br /&gt;
begin&lt;br /&gt;
  if ( Parent[x] &amp;lt;&amp;gt; x ) then&lt;br /&gt;
    Parent[x] := Find ( Parent[x] );&lt;br /&gt;
  Exit ( Parent[x] );&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
procedure Union ( x , y : LongInt );&lt;br /&gt;
begin&lt;br /&gt;
  x := Find ( x );&lt;br /&gt;
  y := Find ( y );&lt;br /&gt;
  if ( x = y ) then exit();&lt;br /&gt;
  if ( Rank[x] &amp;lt; Rank[y] ) then swap ( x , y );&lt;br /&gt;
  &lt;br /&gt;
  Parent[y] := x;&lt;br /&gt;
  if ( Rank[x] = Rank[y] ) then&lt;br /&gt;
    inc ( Rank[x] );&lt;br /&gt;
end;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Лес непересекающихся множеств]]&lt;br /&gt;
&lt;br /&gt;
== Литература ==&lt;br /&gt;
* [https://www.enseignement.polytechnique.fr/informatique/ARCHIVES/IF/03/pi/levy2/fischer-galler.pdf Galler, Bernard A., and Michael J. Fisher. «An improved equivalence algorithm.»] // [[Communications of the ACM]], 7.5 (1964): 301—303.{{ref-en}}&lt;br /&gt;
* [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.435.9355&amp;amp;rep=rep1&amp;amp;type=pdf Tarjan, Robert E., and Jan Van Leeuwen. «Worst-case analysis of set union algorithms.»] // [[Journal of the ACM]] 31.2 (1984): 245—281.{{ref-en}}&lt;br /&gt;
* {{книга&lt;br /&gt;
|автор = Томас Кормен и др.&lt;br /&gt;
|заглавие = Алгоритмы: построение и анализ&lt;br /&gt;
|оригинал = Introduction to Algorithms&lt;br /&gt;
|ссылка = &lt;br /&gt;
|издание = 2-е изд&lt;br /&gt;
|место =  М.&lt;br /&gt;
|издательство = [[Вильямс (издательство)|«Вильямс»]]&lt;br /&gt;
|год = 2006&lt;br /&gt;
|страницы = 1296&lt;br /&gt;
|isbn = 0-07-013151-1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Ссылки ==&lt;br /&gt;
* [https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/UnionFind.pdf Union-Find] / Kevin Wayne, Pearson-Addison Wesley{{ref-en}}&lt;br /&gt;
* [http://staff.ustc.edu.cn/~csli/graduate/algorithms/book6/chap22.htm Chapter 22: Data Structures For Disjoint Sets] / Introduction to Algorithms, Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Rivest{{ref-en}}&lt;br /&gt;
* [https://web.archive.org/web/20140924062309/http://rain.ifmo.ru/cat/view.php/vis/unsorted/disjoint-sets-2003 Визуализатор работы некоторых структур данных для непересекающихся множеств] / ИТМО&lt;br /&gt;
* [http://www.boost.org/doc/libs/1_35_0/libs/disjoint_sets/disjoint_sets.html Реализация непересекающихся множеств в коллекции библиотек C++ Boost], 2006&lt;br /&gt;
&lt;br /&gt;
{{Структуры данных}}&lt;br /&gt;
&lt;br /&gt;
{{rq|refless}}&lt;br /&gt;
[[Категория:Структуры данных]]&lt;/div&gt;</summary>
		<author><name>31.186.66.108</name></author>
	</entry>
</feed>