СНМ (реализация с помощью леса корневых деревьев) — различия между версиями
Nook (обсуждение | вклад) |
Nook (обсуждение | вклад) |
||
Строка 15: | Строка 15: | ||
===Сжатие пути=== | ===Сжатие пути=== | ||
Эта эвристика несколько модифицирует операцию ''get''. Операция get вызывается для элемента ''x'', проходит через несколько вершин и попадает в корень. Все пройденные в этом процессе вершины принадлежат тому же множеству, что и ''x''. Поэтому подвесим (изменим ссылки) их напрямую к корню дерева и, таким образом, уменьшим его высоту. При нерекурсивной реализации операция ''get'' становится двухпроходной. | Эта эвристика несколько модифицирует операцию ''get''. Операция get вызывается для элемента ''x'', проходит через несколько вершин и попадает в корень. Все пройденные в этом процессе вершины принадлежат тому же множеству, что и ''x''. Поэтому подвесим (изменим ссылки) их напрямую к корню дерева и, таким образом, уменьшим его высоту. При нерекурсивной реализации операция ''get'' становится двухпроходной. | ||
+ | |||
+ | ===Псевдокод=== | ||
+ | Для реализации СНМ будем поддерживать следующие массивы: | ||
+ | |||
+ | <tex>p[x]</tex> {{---}} массив "родителей". | ||
+ | |||
+ | <tex>r[x]</tex> {{---}} массив рангов. | ||
+ | ====get==== | ||
+ | get(x) | ||
+ | if p[x] != x | ||
+ | p[x] = get(p[x]) | ||
+ | return p[x] | ||
+ | |||
+ | ====union==== | ||
+ | union(x, y) | ||
+ | x = get(x) | ||
+ | y = get(y) | ||
+ | if r[x] == r[y] | ||
+ | r[x]++ | ||
+ | if r[x] < r[y] | ||
+ | p[x] = y | ||
+ | else | ||
+ | p[y] = x | ||
==Асимптотика== | ==Асимптотика== | ||
Строка 23: | Строка 46: | ||
!Операция !! Истинное время !! Амортизированное время | !Операция !! Истинное время !! Амортизированное время | ||
|- style = "text-align = center" | |- style = "text-align = center" | ||
− | | ''get'' || <tex>O(\log n)</tex> || <tex>O(\alpha(n))</tex> | + | | ''get'' || <tex>O(\log n)</tex> || <tex>O(\alpha(m, n))</tex> |
|- | |- | ||
| ''union'' || <tex>O(1)</tex> || <tex>O(1)</tex> | | ''union'' || <tex>O(1)</tex> || <tex>O(1)</tex> | ||
Строка 31: | Строка 54: | ||
* n {{---}} полное количество элементов | * n {{---}} полное количество элементов | ||
− | * <tex>\alpha(n)</tex> {{---}} функция, обратная к функции Аккермана { | + | * <tex>\alpha(m, n)</tex> {{---}} функция, обратная к функции Аккермана. |
+ | |||
+ | ===Функция Аккермана=== | ||
+ | |||
+ | Функция Аккермана определяется следующим рекуррентным соотношением для целых неотрицательных чисел <tex>m</tex> и <tex>n</tex>: | ||
+ | |||
+ | <tex>A(m, n) = \begin{cases} | ||
+ | 2^n, & m = 1 \\ | ||
+ | 2, & m > 1, n = 0 \\ | ||
+ | A(m - 1, A(m, n - 1)), & m > 1, n > 0 | ||
+ | \end{cases} </tex> | ||
− | + | ====Таблица значений==== | |
+ | |||
+ | {| class="wikitable" border = 1 | ||
+ | |- | ||
+ | !<tex>m \backslash n</tex> !! 0 !! 1 !! 2 !! 3 !! 4 !! 5 | ||
+ | |- style = "text-align = center" | ||
+ | | 1 || 1 || 2 || 4 || 8 || 16 || 32 | ||
+ | |- | ||
+ | | 2 || 2 || 4 || 16 || 65536 || <tex>2^{2^{16}}</tex> || <tex>2^{2^{2^{16}}}</tex> | ||
+ | |- | ||
+ | | 3 || 2 || 16 || <tex>\underbrace{2^{2^{\cdot^{\cdot^{\cdot^2}}}}}_{17}</tex> || <tex>\underbrace{2^{2^{\cdot^{\cdot^{\cdot^2}}}}}_{A(3, 2)}</tex> || <tex>\cdots</tex> || <tex>\cdots</tex> | ||
+ | |- | ||
+ | | 4 || 2 || <tex>\underbrace{2^{2^{\cdot^{\cdot^{\cdot^2}}}}}_{17}</tex> || <tex>\cdots</tex> || <tex>\cdots</tex> || <tex>\cdots</tex> || <tex>\cdots</tex> | ||
+ | |} | ||
==Ссылки== | ==Ссылки== |
Версия 22:19, 14 марта 2012
Система непересекающихся множеств. Реализация с помощью леса корневых деревьев. (disjoint set union (DSU) или Union-Find)
Содержание
Реализация
Каждое множество хранится в виде дерева. Элементы множества хранятся в узлах дерева. У каждого множества есть его представитель — один из элементов этого множества, он хранится в корне дерева. В каждом узле, кроме корня, хранится ссылка на "родителя".
При объединении двух множеств, корень одного дерева подвешивается к другому (операция union). Таким образом, чтобы определить, в каком множестве находится элемент достаточно пройтись по ссылкам по дереву вверх до корня (операция get).
Без использования дополнительных "улучшений", такое дерево может выродиться в линейный список, где get будет работать за линейное время, и никакого выигрыша по сравнению с наивными реализацими не будет. Выигрыш в скорости можно получить, используя две эвристики: объединение по рангу (union by rank) и сжатие пути (path compression).
Объединение по рангу
Эта эвристика аналогична весовой эвристике у связных списков. Идея в том, чтобы при объединении подвешивать дерево с меньшей глубиной к дереву с большей.
Вместо того, чтобы явно хранить высоту дерева, можно хранить его ранг, который по сути является некой верхней оценкой высоты дерева. У дерева, состоящего ровно из одного элемента ранг равен 1. При объединении дерево с меньшим рангом подвешивается к дереву с большим, и ранг объединенного дерева становится равным большему из этих двух рангов. Если ранги объединяемых деревьев равны, то не важно какое к какому дереву подвешивать, но ранг объединенного дерева следует делать большим на 1.
Сжатие пути
Эта эвристика несколько модифицирует операцию get. Операция get вызывается для элемента x, проходит через несколько вершин и попадает в корень. Все пройденные в этом процессе вершины принадлежат тому же множеству, что и x. Поэтому подвесим (изменим ссылки) их напрямую к корню дерева и, таким образом, уменьшим его высоту. При нерекурсивной реализации операция get становится двухпроходной.
Псевдокод
Для реализации СНМ будем поддерживать следующие массивы:
— массив "родителей".
— массив рангов.
get
get(x) if p[x] != x p[x] = get(p[x]) return p[x]
union
union(x, y) x = get(x) y = get(y) if r[x] == r[y] r[x]++ if r[x] < r[y] p[x] = y else p[y] = x
Асимптотика
- см. также Анализ реализации с ранговой эвристикой
Операция | Истинное время | Амортизированное время |
---|---|---|
get | ||
union |
- m — общее количество операций
- n — полное количество элементов
- — функция, обратная к функции Аккермана.
Функция Аккермана
Функция Аккермана определяется следующим рекуррентным соотношением для целых неотрицательных чисел
и :
Таблица значений
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
1 | 1 | 2 | 4 | 8 | 16 | 32 |
2 | 2 | 4 | 16 | 65536 | ||
3 | 2 | 16 | ||||
4 | 2 |
Ссылки
- Система непересекающихся множеств — описание этой реализации на habrahabr.ru
- Функция Аккермана — Википедия
Литература
- Томас Кормен, Чарльз Лейзерсон, Рональд Ривест, Клиффорд Штайн. Алгоритмы. Построение и анализ — Вильямс, 2010. - 1296с. — ISBN 978-5-8459-0857-4, 0-07-013151-1. (стр 589)