Алгоритм Краскала [1] находит минимальный остовный лес неориентированного графа, взвешенного по ребрам . Если граф связен , он находит минимальное остовное дерево . Это жадный алгоритм , который на каждом шаге добавляет в лес ребро с наименьшим весом, которое не образует цикл . [2] Ключевыми этапами алгоритма являются сортировка и использование структуры данных с непересекающимися наборами для обнаружения циклов. Во время его работы преобладает время сортировки всех ребер графа по их весу.
Минимальное остовное дерево связного взвешенного графа — это связный подграф без циклов, для которого сумма весов всех ребер в подграфе минимальна. Для несвязного графа минимальный остовный лес состоит из минимального остовного дерева для каждого компонента связности .
Этот алгоритм был впервые опубликован Джозефом Крускалом в 1956 году [3] и вскоре после этого был заново открыт Лоберманом и Вайнбергером (1957). [4] Другие алгоритмы решения этой проблемы включают алгоритм Борувки , алгоритм Ярника и алгоритм обратного удаления .
Алгоритм выполняет следующие шаги:
По завершении алгоритма лес образует минимальный остовный лес графа. Если граф связен, лес состоит из одного компонента и образует минимальное остовное дерево.
Следующий код реализован с помощью структуры данных с непересекающимся набором данных . Он представляет лес F как набор ненаправленных ребер и использует структуру данных непересекающихся наборов для эффективного определения того, являются ли две вершины частью одного и того же дерева.
алгоритм Крускала ( G ) Ф:= ∅ для каждого v в GV сделайте MAKE-SET(v) для каждого {u, v} в GE, упорядоченного по весу ({u, v}), увеличивая do , если FIND-SET(u) ≠ FIND-SET(v), то F := F ∪ { {u, v} } СОЮЗ(НАЙТИ-НАБОР(u), НАЙТИ-НАБОР(v)) вернуть F
Можно показать , что для графа с E ребрами и V вершинами алгоритм Краскала работает за время O ( E log E ) с простыми структурами данных. Здесь O выражает время в большой записи O , а log — это логарифм , который можно принять как натуральный логарифм, так и двоичный логарифм : внутри O -нотации два вида логарифма эквивалентны, поскольку они различаются постоянным коэффициентом. . Вместо этого эту временную границу часто записывают как O ( E log V ) , что эквивалентно для графов без изолированных вершин, поскольку для этих графов V /2 ≤ E < V 2 и логарифмы V и E снова находятся в пределах постоянного множителя. друг друга.
Чтобы достичь этой границы, сначала отсортируйте ребра по весу, используя сортировку сравнения за время O ( E log E ) . После сортировки можно перебирать ребра в отсортированном порядке за постоянное время для каждого ребра. Затем используйте структуру данных с непересекающимся набором с набором вершин для каждого компонента, чтобы отслеживать, какие вершины в каких компонентах находятся. Создание этой структуры с отдельным набором для каждой вершины требует V операций и времени O ( V ) . Последняя итерация по всем ребрам выполняет две операции поиска и, возможно, одну операцию объединения для каждого ребра. Эти операции занимают амортизированное время O ( α ( V )) на операцию, что дает общее время O ( Eα ( V )) для этого цикла в наихудшем случае , где α — крайне медленно растущая обратная функция Аккермана . Эта часть временной границы намного меньше времени этапа сортировки, поэтому общее время алгоритма можно упростить до времени этапа сортировки.
В тех случаях, когда ребра уже отсортированы или они имеют достаточно малый целочисленный вес, чтобы позволить алгоритмам целочисленной сортировки , таким как сортировка по подсчету или поразрядная сортировка, сортировать их за линейное время, операции с непересекающимися множествами являются самой медленной оставшейся частью алгоритма, и общее время составляет O ( E α( V )) .
Доказательство состоит из двух частей. Во-первых, доказывается, что алгоритм создает связующее дерево . Во-вторых, доказывается, что построенное остовное дерево имеет минимальный вес.
Пусть это связный взвешенный граф и пусть это подграф, созданный алгоритмом. не может иметь цикл, поскольку по определению ребро не добавляется, если оно приводит к образованию цикла. не может быть отключен, так как первое встреченное ребро, соединяющее два компонента, было бы добавлено алгоритмом. Таким образом, является связующим деревом .
По индукции мы показываем, что следующее предложение P истинно : если F — множество ребер, выбранных на любом этапе алгоритма, то существует некоторое минимальное остовное дерево, которое содержит F и ни одно из ребер, отклоненных алгоритмом.
Алгоритм Краскала по своей сути последователен и его трудно распараллелить. Однако можно выполнить первоначальную сортировку ребер параллельно или, альтернативно, использовать параллельную реализацию двоичной кучи для извлечения ребра минимального веса на каждой итерации. [5] Поскольку параллельная сортировка возможна во времени на процессорах, [6] время выполнения алгоритма Краскала может быть уменьшено до O ( E α( V )), где α снова является обратной однозначной функцией Аккермана .
Вариант алгоритма Крускала, названный Фильтр-Краскал, был описан Осиповым и др. [7] и лучше подходит для распараллеливания. Основная идея Filter-Kruskal состоит в том, чтобы разделить ребра аналогично быстрой сортировке и отфильтровать ребра, соединяющие вершины одного и того же дерева, чтобы снизить затраты на сортировку. Следующий псевдокод демонстрирует это.
функция filter_kruskal(G) — это if |GE| < kruskal_threshold: return kruskal(G) точка поворота = select_random(GE) E ≤ , E > = раздел (GE, точка поворота) A = filter_kruskal(E ≤ ) E > = фильтр (E > ) A = A ∪ filter_kruskal(E > ) return Aфункция part(E, Pivot) равна E ≤ = ∅, E > = ∅ foreach (u, v) в E do , если вес (u, v) ≤ Pivot , то E ≤ = E ≤ ∪ {(u, v)} else E > = E > ∪ {(u, v)} return E ≤ , E >функция filter(E) равна E f = ∅ foreach (u, v) в E do , если find_set(u) ≠ find_set(v) , то E f = E f ∪ {(u, v)} return E f
Фильтр-Крускал лучше подходит для распараллеливания, поскольку сортировку, фильтрацию и секционирование можно легко выполнять параллельно, распределяя ребра между процессорами. [7]
Наконец, были исследованы другие варианты параллельной реализации алгоритма Краскала. Примеры включают схему, которая использует вспомогательные потоки для удаления ребер, которые определенно не являются частью MST в фоновом режиме, [8] и вариант, который запускает последовательный алгоритм на p подграфах, а затем объединяет эти подграфы до тех пор, пока не останется только один, последний MST. останки. [9]
{{cite book}}
: CS1 maint: несколько имен: список авторов ( ссылка )