СНМ (наивные реализации) — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 1: Строка 1:
 
{{Определение
 
{{Определение
 
| definition =
 
| definition =
Система непересекающихся множеств (disjoint set union, DSU) {{ --- }} структура данных, поддерживающая операции <tex>union(x, y)</tex> {{ --- }} объединения множеств, содержащих <tex>x</tex> и <tex>y</tex>, и <tex>find(k)</tex> {{ --- }} поиск множества, которому принадлежит элемент <tex>k</tex>.
+
Система непересекающихся множеств (disjoint set union, DSU) {{ --- }} структура данных, поддерживающая операции union(x, y) {{ --- }} объединения множеств, содержащих x и y, и find(k) {{ --- }} поиск множества, которому принадлежит элемент k.
 
}}
 
}}
  
Строка 7: Строка 7:
  
 
== Пример работы ==  
 
== Пример работы ==  
<!-- [[Файл:DSU_1_Example.png|600px|thumb|right|Пример работы]] -->
 
 
[[Файл:DSU_1_Example.png|400px]]
 
[[Файл:DSU_1_Example.png|400px]]
  
Строка 13: Строка 12:
 
=== С помощью массива "цветов" ===
 
=== С помощью массива "цветов" ===
 
'''Оценка работы:'''
 
'''Оценка работы:'''
{| border="1"
+
{| class="wikitable" border="1"
  |<tex>init</tex>
+
  |init
  |<tex>find</tex>
+
  |find
  |<tex>union</tex>
+
  |union
 
  |-
 
  |-
 
  |<tex>O(n)</tex>
 
  |<tex>O(n)</tex>
Строка 22: Строка 21:
 
  |<tex>O(n)</tex>
 
  |<tex>O(n)</tex>
 
  |}
 
  |}
Введем массив <tex>color</tex>, в <tex>color[i]</tex> будет храниться цвет множества, к которому принадлежит <tex>i</tex>. Тогда <tex>find</tex>, очевидно, будет работать за <tex>O(1)</tex>.
+
Введем массив s, в s[i] будет храниться цвет множества, к которому принадлежит i. Тогда find, очевидно, будет работать за <tex>O(1)</tex>.
  
Чтобы объединить множества <tex>x</tex> и <tex>y</tex>, надо изменить все <tex>color[i]</tex>, равные цвету <tex>x</tex>, на цвет <tex>y</tex>. Тогда <tex>union</tex> работает за <tex>O(n)</tex>.
+
Чтобы объединить множества x и y, надо изменить все s[i], равные цвету x, на цвет y. Тогда union работает за <tex>O(n)</tex>.
  
 
'''Псевдокод:'''
 
'''Псевдокод:'''
  int color[n]
+
  int s[n]
 
  init():
 
  init():
 
     for i = 0 to n - 1:
 
     for i = 0 to n - 1:
         color[i] = i //сначала каждый элемент лежит в своем множестве
+
         s[i] = i // сначала каждый элемент лежит в своем множестве
 
   
 
   
 
  find(k):
 
  find(k):
     return color[k]
+
     return s[k]
 
   
 
   
 
  union(x, y):
 
  union(x, y):
     if color[x] == color[y]:
+
     if s[x] == s[y]:
 
         return
 
         return
 
     else:
 
     else:
         t = color[y]
+
         t = s[y]
 
         for i = 0 to n - 1:
 
         for i = 0 to n - 1:
             if color[i] == t:
+
             if s[i] == t:
                 color[i] = color[x]
+
                 s[i] = s[x]
  
 
=== С помощью списка ===
 
=== С помощью списка ===
 
'''Оценка работы:'''
 
'''Оценка работы:'''
{| border="1"
+
{| class="wikitable" border="1"
  |<tex>init</tex>
+
  |init
  |<tex>find</tex>
+
  |find
  |<tex>union</tex>
+
  |union
 
  |-
 
  |-
 
  |<tex>O(n)</tex>
 
  |<tex>O(n)</tex>
Строка 55: Строка 54:
 
  |<tex>O(1)</tex>
 
  |<tex>O(1)</tex>
 
  |}
 
  |}
Пусть каждое множество хранится в виде списка. Вначале создается <tex>n</tex> списков, в котором каждый элемент является представителем своего множества. Для каждого списка будем хранить ссылку на следующий элемент <tex>(next)</tex> и ссылку на голову (<tex>head</tex>). Тогда для объединения множеств надо будет просто перекинуть ссылку <tex>next</tex> на начало другого множества. Таким образом, <tex>union</tex> работает за <tex>O(1)</tex>.
+
Будем хранить множество в виде списка. Вначале создается n списков, в котором каждый элемент является представителем своего множества. Для каждого списка будем хранить ссылку на следующий элемент (next) и ссылку на голову (head). Тогда для объединения множеств надо будет просто перекинуть ссылку next на начало другого множества. Таким образом, union работает за <tex>O(1)</tex>.
  
Для того, чтобы найти элемент в одном из множеств, надо идти по ссылкам <tex>next</tex>, пока он не указывает на <tex>null</tex> {{ --- }} тогда мы нашли элемент-представитель. Таким образом, <tex>find</tex> работает за <tex>O(n)</tex>.
+
Для того, чтобы найти элемент в одном из множеств, надо идти по ссылкам next, пока он не указывает на null {{ --- }} тогда мы нашли элемент-представитель. Таким образом, find работает за <tex>O(n)</tex>.
  
 
Псевдокод:
 
Псевдокод:
Строка 67: Строка 66:
 
         s[i].head = s[i]
 
         s[i].head = s[i]
 
   
 
   
  find(x): //подразумевается, что x - ссылка на один из элементов
+
  find(x): // подразумевается, что x {{ --- }} ссылка на один из элементов
 
     while x.next != null:
 
     while x.next != null:
 
         x = x.next
 
         x = x.next
 
     return x.set
 
     return x.set
 
   
 
   
  union(x, y): //здесь важно, что x и y - представители множеств
+
  union(x, y): // здесь важно, что x и y {{ --- }} представители множеств
 
     if x == y:
 
     if x == y:
 
         return
 
         return
 
     else:
 
     else:
         x.next = y.head //соединили списки
+
         x.next = y.head // соединили списки
         y.head = x.head //сделали корректную ссылку на голову для представителя нового списка
+
         y.head = x.head // сделали корректную ссылку на голову для представителя нового списка
  
 
'''Пример работы:'''
 
'''Пример работы:'''
  
Два списка до операции <tex>union</tex>:
+
Два списка до операции union:
  
 
[[Файл:DSU_1_X.png]]
 
[[Файл:DSU_1_X.png]]
Строка 87: Строка 86:
 
[[Файл:DSU_1_Y.png]]
 
[[Файл:DSU_1_Y.png]]
  
Два списка после операции <tex>union</tex>:
+
Два списка после операции union:
  
 
[[Файл:DSU_1_XY.png]]
 
[[Файл:DSU_1_XY.png]]

Версия 22:24, 14 марта 2012

Определение:
Система непересекающихся множеств (disjoint set union, DSU) — структура данных, поддерживающая операции union(x, y) — объединения множеств, содержащих x и y, и find(k) — поиск множества, которому принадлежит элемент k.


Пример работы

DSU 1 Example.png

Реализации

С помощью массива "цветов"

Оценка работы:

init find union
[math]O(n)[/math] [math]O(1)[/math] [math]O(n)[/math]

Введем массив s, в s[i] будет храниться цвет множества, к которому принадлежит i. Тогда find, очевидно, будет работать за [math]O(1)[/math].

Чтобы объединить множества x и y, надо изменить все s[i], равные цвету x, на цвет y. Тогда union работает за [math]O(n)[/math].

Псевдокод:

int s[n]
init():
    for i = 0 to n - 1:
        s[i] = i // сначала каждый элемент лежит в своем множестве

find(k):
    return s[k]

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]

С помощью списка

Оценка работы:

init find union
[math]O(n)[/math] [math]O(n)[/math] [math]O(1)[/math]

Будем хранить множество в виде списка. Вначале создается n списков, в котором каждый элемент является представителем своего множества. Для каждого списка будем хранить ссылку на следующий элемент (next) и ссылку на голову (head). Тогда для объединения множеств надо будет просто перекинуть ссылку next на начало другого множества. Таким образом, union работает за [math]O(1)[/math].

Для того, чтобы найти элемент в одном из множеств, надо идти по ссылкам next, пока он не указывает на null — тогда мы нашли элемент-представитель. Таким образом, find работает за [math]O(n)[/math].

Псевдокод:

s[n]
init():
    for i = 0 to n - 1:
        s[i].set = i
        s[i].next = null
        s[i].head = s[i]

find(x): // подразумевается, что x — ссылка на один из элементов
    while x.next != null:
        x = x.next
    return x.set

union(x, y): // здесь важно, что x и y — представители множеств
    if x == y:
        return
    else:
        x.next = y.head // соединили списки
        y.head = x.head // сделали корректную ссылку на голову для представителя нового списка

Пример работы:

Два списка до операции union:

DSU 1 X.png

DSU 1 Y.png

Два списка после операции union:

DSU 1 XY.png

Другие реализации

Источники

  • Т. Кормен - Алгоритмы, построение и анализ. Второе издание. Часть V. Глава 21.

Ссылки