Menu
Coddy logo textTech

Алгоритм Прима

Последнее обновление

Алгоритм Прима строит минимальное остовное дерево (MST) - самый дешёвый набор рёбер, соединяющий все узлы без циклов - выращивая одно дерево наружу от стартового узла. На каждом шаге он рассматривает все рёбра, пересекающие границу между деревом и узлом вне его, и добавляет самое дешёвое. Нажмите воспроизведение выше, чтобы увидеть, как дерево расширяется, всегда беря ребро наименьшего веса, ведущее к новому узлу.

Поскольку он всегда выбирает минимальное пересекающее ребро, каждое добавление безопасно (гарантированно является частью некоторого MST). С очередью с приоритетом на основе двоичной кучи, ключом которой является самое дешёвое ребро к каждому внешнему узлу, Прим работает за O(E log V). Он контрастирует с Крускалом, который сортирует все рёбра глобально, вместо того чтобы выращивать одно связное дерево.

Временная и пространственная сложность

РеализацияСложностьПримечания
Двоичная кучаO(E log V)Очередь с приоритетом пересекающих рёбер
Матрица смежностиO(V²)Проще; подходит для плотных графов
ПамятьO(V + E)Принадлежность дереву + очередь с приоритетом
Лучше всего дляПлотных графовРастёт от одного стартового узла

Пошагово

ШагЧто происходит
1Начните дерево с любого одного узла.
2Рассмотрите все рёбра, пересекающие границу между деревом и узлом вне его.
3Выберите пересекающее ребро с наименьшим весом.
4Добавьте это ребро и его новый узел в дерево.
5Повторяйте, пока все узлы не окажутся в дереве.

Разобранный пример

Построение MST графа из 4 узлов с рёбрами A-B=1, A-C=3, B-C=2, B-D=4, C-D=5, начиная с A:

ШагДеревоПересекающие рёбраВыбранное ребро
1{A}A-B=1, A-C=3A-B (вес 1)
2{A, B}A-C=3, B-C=2, B-D=4B-C (вес 2)
3{A, B, C}B-D=4, C-D=5B-D (вес 4)
4{A, B, C, D}нет - все узлы в деревеготово: вес MST 1+2+4 = 7

Когда использовать алгоритм Прима

Используйте, когдаИзбегайте, когда
Вам нужно минимальное остовное дерево связного неориентированного взвешенного графа.Граф ориентированный или вам нужны кратчайшие пути - используйте вместо этого Дейкстру или Беллмана-Форда.
Граф плотный (E близко к ); матричная форма O(V²) проста и быстра.Граф разреженный, а рёбра уже отсортированы или их легко отсортировать - Крускал часто проще.
Вы хотите, чтобы дерево росло из одной области наружу (например, инкрементальная разметка сети).Граф несвязный - Прим охватывает только одну компоненту; вам нужен минимальный остовный лес.
У вас уже есть доступная структура смежности и очередь с приоритетом.Вам нужно обнаруживать циклы по глобальному набору рёбер - union-find (Крускал) лучше подходит для этой задачи.

Код Prim's Algorithm

Чистая, готовая к запуску реализация Prim's Algorithm на Python, JavaScript, Java, C++, C. Выберите язык, скопируйте код или откройте его уже загруженным в плейграунде Coddy.

Код Prim's Algorithm на Python

Python
1import heapq2
3
4def prim(graph, start):5    visited = {start}6    heap = [(w, start, v) for v, w in graph[start]]7    heapq.heapify(heap)8    mst, total = [], 09    while heap and len(visited) < len(graph):10        w, u, v = heapq.heappop(heap)11        if v in visited:12            continue13        visited.add(v)14        mst.append((u, v, w))15        total += w16        # Offer the new node's edges to the frontier17        for neighbor, weight in graph[v]:18            if neighbor not in visited:19                heapq.heappush(heap, (weight, v, neighbor))20    return mst, total21
22
23graph = {24    "A": [("B", 4), ("C", 1)],25    "B": [("A", 4), ("C", 3), ("D", 2)],26    "C": [("A", 1), ("B", 3), ("D", 5)],27    "D": [("B", 2), ("C", 5), ("E", 7)],28    "E": [("D", 7)],29}30
31mst, total = prim(graph, "A")32for u, v, w in mst:33    print(f"{u} - {v} (weight {w})")34print("Total MST weight:", total)
Запустите этот код в плейграунде Python

Часто задаваемые вопросы об алгоритме Прима

Какова временная сложность алгоритма Прима?
С очередью с приоритетом на основе двоичной кучи Прим работает за O(E log V). Более простая версия с матрицей смежности, которая на каждом шаге ищет минимальное пересекающее ребро, имеет сложность O(V²), что может быть быстрее на плотных графах. Обе используют память O(V + E).
В чём разница между алгоритмами Прима и Крускала?
Оба находят минимальное остовное дерево жадным образом. Прим выращивает одно связное дерево от стартового узла, многократно добавляя самое дешёвое ребро, выходящее из дерева (используя очередь с приоритетом). Крускал рассматривает все рёбра, отсортированные по весу, и добавляет самое дешёвое, не образующее цикл (используя union-find). Прим часто предпочтителен на плотных графах, Крускал - на разреженных.
Всегда ли алгоритм Прима находит оптимальное MST?
Да. На каждом шаге самое дешёвое ребро, пересекающее текущее дерево, безопасно добавлять - оно принадлежит некоторому минимальному остовному дереву (свойство разреза). Многократное добавление безопасных рёбер даёт настоящее минимальное остовное дерево при условии, что граф связный.
Когда следует использовать алгоритм Прима вместо Крускала?
Обращайтесь к Приму, когда граф плотный, потому что его матричная форма O(V²) избегает сортировки всех E рёбер и выращивает одно дерево от стартового узла. Крускал блистает на разреженных графах, где сортировка списка рёбер дёшева, а union-find обеспечивает быстрые проверки циклов. Оба дают корректное MST, поэтому выбор зависит главным образом от плотности рёбер и от того, какие структуры данных у вас уже есть.
Влияет ли стартовый узел на итоговое MST?
Нет - суммарный вес MST одинаков независимо от того, с какого узла вы начинаете, потому что вес минимального остовного дерева связного графа уникален. Конкретные рёбра могут различаться только тогда, когда несколько рёбер имеют одинаковый вес и существует несколько MST. В остальных случаях Прим приходит к точно такому же дереву независимо от стартового узла.
Может ли алгоритм Прима работать с несвязными графами?
Не напрямую. Прим выращивает одно дерево, поэтому охватывает только связную компоненту, содержащую стартовый узел, оставляя остальное нетронутым. Чтобы покрыть каждую компоненту, вы бы многократно запускали Прим от непосещённого узла, получая минимальный остовный лес вместо одного дерева.
Coddy programming languages illustration

Освойте алгоритмы с Coddy

НАЧАТЬ