СНМ (наивные реализации) — различия между версиями
| Nastya (обсуждение | вклад)  (→С помощью массива) | Nastya (обсуждение | вклад)   (→С помощью списка) | ||
| Строка 64: | Строка 64: | ||
|   |}--> |   |}--> | ||
| − | Будем хранить множество в виде списка. Для каждого элемента списка храним ссылку на следующий элемент и указатель на head, который является представителем. Для того чтобы найти представителя, нужно перейти по ссылке на head. Значит find работает за <tex> O(1) </tex>. | + | Будем хранить множество в виде списка. Для каждого элемента списка храним ссылку на следующий элемент и указатель на <tex> head </tex>, который является представителем. Для того чтобы найти представителя, нужно перейти по ссылке на <tex> head </tex>. Значит <math> \mathrm{find} </math> работает за <tex> O(1) </tex>. | 
| − | Для объединения множеств потребуется объединить два списка и обновить ссылки на head. Таким образом, union работает за <tex> O(n) </tex>. | + | Для объединения множеств потребуется объединить два списка и обновить ссылки на <tex> head </tex>. Таким образом, <math> \mathrm{union} </math> работает за <tex> O(n) </tex>. | 
| − | Чтобы объединить два списка, нужно хранить ссылку на tail. Ее можно хранить в голове списка. | + | Чтобы объединить два списка, нужно хранить ссылку на <tex> tail </tex>. Ее можно хранить в голове списка. | 
| − |   s[n] | + | <code> | 
| − |   init(): | + |   '''int''' s[n] | 
| − |       for i = 0 to n - 1 | + |   '''func''' init(): | 
| + |       '''for''' i = 0 '''to''' n - 1 | ||
|           s[i].data = i |           s[i].data = i | ||
|           s[i].next = null |           s[i].next = null | ||
|           s[i].head = s[i] |           s[i].head = s[i] | ||
| − | + | </code>  | |
| − |   find(x): // подразумевается, что x {{ --- }} ссылка на один из элементов | + | <code> | 
| − |       return x.head.data | + |   '''int''' find(x): <font color=green> // подразумевается, что <tex> x </tex> {{ --- }} ссылка на один из элементов </font> | 
| − | + |       '''return''' x.head.data | |
| − |   union(x, y): // x и y {{ --- }} элементы множеств | + | </code>  | 
| + | <code> | ||
| + |   '''func''' union('''int''' x, '''int''' y): <font color=green> // <tex> x </tex> и <tex> y </tex> {{ --- }} элементы множеств</font> | ||
|       x = x.head |       x = x.head | ||
|       y = y.head |       y = y.head | ||
| − |       if x == y | + |       '''if''' x == y | 
| − |           return | + |           '''return''' | 
| − |       // соединим списки | + |       <font color=green> // соединим списки </font> | 
|       x.tail.next = y |       x.tail.next = y | ||
| − |       // сделаем корректную ссылку на tail в head | + |       <font color=green> // сделаем корректную ссылку на <tex> tail </tex> в <tex> head</tex></font> | 
|       x.tail = y.tail |       x.tail = y.tail | ||
| − |       // скорректируем ссылки на head у элементов множества  | + |       <font color=green> // скорректируем ссылки на <tex> head </tex> у элементов множества <tex> y </tex> </font> | 
| − |       while y  | + |       '''while''' y <tex> \neq </tex> null | 
|           y.head = x |           y.head = x | ||
|           y = y.next |           y = y.next | ||
| − | + | </code> | |
| [[Файл:DSU_list_example.png|800px|left|thumb|Пример объединения двух множеств (union)]] | [[Файл:DSU_list_example.png|800px|left|thumb|Пример объединения двух множеств (union)]] | ||
| <br clear="all"/> | <br clear="all"/> | ||
Версия 10:30, 11 июня 2014
Система (лес, объединение) непересекающихся множеств (СНМ, disjoint set forest, DSF, disjoint set union, DSU) — иерархическая структура данных, позволяющая эффективно работать с множествами.
Содержание
Описание
Структура хранит набор объектов (например, чисел от до ) в виде непересекающихся множеств. У каждого множества есть конкретный представитель.
Определены две операции:
- — объединяет множества, содержащие и
- — возвращает представителя множества, в котором находится
Для любого элемента множества представитель всегда одинаковый. Поэтому чтобы проверить принадлежность элементов и одному множеству достаточно сравнить и .
Реализации
С помощью массива
Пусть в массиве s хранятся номера множеств, в будет храниться номер множества, к которому принадлежит . Этот номер отождествляет множество, возвращает именно его. Тогда , очевидно, будет работать за .
Чтобы объединить множества  и , надо изменить все , равные номеру множества , на номер . Тогда union работает за .
int s[n]
func init():
    for i = 0 to n - 1
        s[i] = i                // сначала каждый элемент лежит в своем множестве 
 
int find(k):
    return s[k]
 
func union(x, y):
    if s[x] == s[y]
        return
    else
        t = s[y]
        for i = 0 to n - 1
            if s[i] == t
                s[i] = s[x]
С помощью списка
Будем хранить множество в виде списка. Для каждого элемента списка храним ссылку на следующий элемент и указатель на , который является представителем. Для того чтобы найти представителя, нужно перейти по ссылке на . Значит работает за .
Для объединения множеств потребуется объединить два списка и обновить ссылки на . Таким образом, работает за . Чтобы объединить два списка, нужно хранить ссылку на . Ее можно хранить в голове списка.
int s[n]
func init():
    for i = 0 to n - 1
        s[i].data = i
        s[i].next = null
        s[i].head = s[i]
 
int find(x):  // подразумевается, что  — ссылка на один из элементов 
    return x.head.data
 
func union(int x, int y): // и — элементы множеств x = x.head y = y.head if x == y return // соединим списки x.tail.next = y // сделаем корректную ссылку на в x.tail = y.tail // скорректируем ссылки на у элементов множества while y null y.head = x y = y.next
Другие реализации
Источники
- Т. Кормен - Алгоритмы, построение и анализ. Второе издание. Часть V. Глава 21.


