正在载入交互式动画窗口请稍等

Prim(普里姆)算法 可视化交互式动画版

图码-数据结构可视化动画版

Prim的算法简介:

我们已经讨论了  最小生成树的 Kruskal 算法 与Kruskal算法一样,Prim算法也是一种  贪心算法 该算法始终从单个节点开始,然后移动到多个相邻节点,以便探索沿途所有连接的边。

该算法从空的生成树开始。 这个想法是维护两组顶点。 第一个集合包含已包含在 MST 中的顶点,另一个集合包含尚未包含在 MST 中的顶点。 在每一步中,它都会考虑连接两个集合的所有边,并从这些边中选择最小权重边。 拾取边后,它将边的另一个端点移动到包含 MST 的集合。 

连接图中两组顶点的一组边  在图论中称为割 因此,在 Prim 算法的每一步中,找到一个切割,从切割中选取最小权重边,并将该顶点包含在 MST 集合(包含已包含顶点的集合)中。

Prim 算法如何工作? 

Prim 算法的工作原理可以通过以下步骤来描述:

步骤1: 确定任意一个顶点作为MST的起始顶点。
步骤2: 按照步骤3到5,直到出现未包含在MST中的顶点(称为边缘顶点)。
步骤3: 找到连接任意树顶点和边缘顶点的边。
第四步: 找到这些边中的最小值。
步骤5: 如果选择的边不形成任何环,则将其添加到MST中。
步骤6: 返回MST并退出

注意: 为了确定环,我们可以将顶点分为两组[一组包含MST中包含的顶点,另一组包含边缘顶点。]

Prim算法说明:

以下图为例,我们需要找到最小生成树(MST)。

图表示例

图表示例

步骤1: 首先,我们选择一个任意顶点作为最小生成树的起始顶点。 这里我们选择顶点 0 作为起始顶点。

选择 0 作为起始顶点

选择 0 作为起始顶点

步骤2: 连接不完整MST和其他顶点的所有边都是边{0, 1}和{0, 7}。 在这两者之间,权重最小的边是{0, 1}。 因此,将边和顶点 1 包含在 MST 中。

MST中添加1

MST中添加1

  步骤3: 连接不完整MST到其他顶点的边是{0, 7}、{1, 7}和{1, 2}。 在这些边中,边{0, 7}和{1, 2}的最小权重为8。 让我们在 MST 中包含边 {0, 7} 和顶点 7。 [我们还可以在 MST 中包含边 {1, 2} 和​​顶点 2]。 

MST中添加7

MST中添加7

步骤4: 连接不完整MST与边缘顶点的边为{1, 2}、{7, 6}和{7, 8}。 将边 {7, 6} 和顶点 6 添加到 MST 中,因为它的权重最小(即 1)。

MST中添加6

MST中添加6

第 5 步: 连接边现在为 {7, 8}、{1, 2}、{6, 8} 和 {6, 5}。 将边{6, 5}和顶点5包含在MST中,因为其中边的权重最小(即2)。

将顶点 5 包含在 MST 中

将顶点 5 包含在 MST 中

步骤6: 当前连接边中,边{5, 2}的权重最小。 因此,将该边和顶点 2 包含在 MST 中。

将顶点 2 包含在 MST 中

将顶点 2 包含在 MST 中

步骤7: 不完整MST与其他边的连接边为{2, 8}、{2, 3}、{5, 3}和{5, 4}。 权重最小的边是边 {2, 8},其权重为 2。因此,将该边和顶点 8 包含在 MST 中。

在 MST 中添加顶点 8

在 MST 中添加顶点 8

步骤8: 看到这里,边{7, 8}和{2, 3}都具有相同的权重,并且权重最小。 但 7 已经是 MST 的一部分。 因此,我们将考虑边 {2, 3} 并将该边和顶点 3 包含在 MST 中。

在 MST 中包含顶点 3

在 MST 中包含顶点 3

步骤9: 仅保留顶点4。 从不完整的MST到4的最小加权边是{3, 4}。

将顶点 4 包含在 MST 中

将顶点 4 包含在 MST 中

MST的最终结构如下,MST边的权重为 (4 + 8 + 1 + 2 + 4 + 2 + 7 + 9) = 37

使用上述方法形成的MST的结构

使用上述方法形成的MST的结构

注意: 如果我们在第三步中选择了边 {1, 2},则 MST 将如下所示。

如果我们在 MST 中选择了边 {1, 2},则备用 MST 的结构

如果我们在 MST 中选择了边 {1, 2},则备用 MST 的结构

如何实现Prim算法?

按照给定的步骤使用上面提到的 Prim 算法 来查找图的 MST:

  • 创建一个 mstSet 集来跟踪已包含在 MST 中的顶点。 
  • 为输入图中的所有顶点分配一个键值。 将所有键值初始化为 INFINITE。 将第一个顶点的键值指定为 0,以便首先选取它。 
  • 虽然 mstSet 不包含所有顶点 
    • 选择一个不在 mstSet 中且具有最小键值的  顶点 u 。
    • 将u 包含 mstSet 中。 
    • 更新u 所有相邻顶点的键值 要更新键值,请迭代所有相邻顶点。 
      • 对于每个相邻顶点 v ,如果边 uv 的权重 小于 v 的前一个键值,则将键值更新为 uv 的权重。

使用关键值的想法是从 切割 中选取最小权重边缘。 键值仅用于尚未包含在 MST 中的顶点,这些顶点的键值表示将它们连接到 MST 中包含的顶点集的最小权重边。

下面是该方法的实现:

C++

// A C++ program for Prim's Minimum
// Spanning Tree (MST) algorithm. The program is
// for adjacency matrix representation of the graph
 
#include <bits/stdc++.h>
using namespace std;
 
// Number of vertices in the graph
#define V 5
 
// A utility function to find the vertex with
// minimum key value, from the set of vertices
// not yet included in MST
int minKey(int key[], bool mstSet[])
{
    // Initialize min value
    int min = INT_MAX, min_index;
 
    for (int v = 0; v < V; v++)
        if (mstSet[v] == false && key[v] < min)
            min = key[v], min_index = v;
 
    return min_index;
}
 
// A utility function to print the
// constructed MST stored in parent[]
void printMST(int parent[], int graph[V][V])
{
    cout << "Edge \tWeight\n";
    for (int i = 1; i < V; i++)
        cout << parent[i] << " - " << i << " \t"
             << graph[i][parent[i]] << " \n";
}
 
// Function to construct and print MST for
// a graph represented using adjacency
// matrix representation
void primMST(int graph[V][V])
{
    // Array to store constructed MST
    int parent[V];
 
    // Key values used to pick minimum weight edge in cut
    int key[V];
 
    // To represent set of vertices included in MST
    bool mstSet[V];
 
    // Initialize all keys as INFINITE
    for (int i = 0; i < V; i++)
        key[i] = INT_MAX, mstSet[i] = false;
 
    // Always include first 1st vertex in MST.
    // Make key 0 so that this vertex is picked as first
    // vertex.
    key[0] = 0;
   
    // First node is always root of MST
    parent[0] = -1;
 
    // The MST will have V vertices
    for (int count = 0; count < V - 1; count++) {
         
        // Pick the minimum key vertex from the
        // set of vertices not yet included in MST
        int u = minKey(key, mstSet);
 
        // Add the picked vertex to the MST Set
        mstSet[u] = true;
 
        // Update key value and parent index of
        // the adjacent vertices of the picked vertex.
        // Consider only those vertices which are not
        // yet included in MST
        for (int v = 0; v < V; v++)
 
            // graph[u][v] is non zero only for adjacent
            // vertices of m mstSet[v] is false for vertices
            // not yet included in MST Update the key only
            // if graph[u][v] is smaller than key[v]
            if (graph[u][v] && mstSet[v] == false
                && graph[u][v] < key[v])
                parent[v] = u, key[v] = graph[u][v];
    }
 
    // Print the constructed MST
    printMST(parent, graph);
}
 
// Driver's code
int main()
{
    int graph[V][V] = { { 0, 2, 0, 6, 0 },
                        { 2, 0, 3, 8, 5 },
                        { 0, 3, 0, 0, 7 },
                        { 6, 8, 0, 0, 9 },
                        { 0, 5, 7, 9, 0 } };
 
    // Print the solution
    primMST(graph);
 
    return 0;
}
 
// This code is contributed by rathbhupendra


            

C

Java

Python3

C#

Javascript

输出

边重
0 - 1 2
1 - 2 3
0 - 3 6
1 - 4 5



时间复杂度: O(V 2 ),如果输入 图使用邻接表表示 ,那么Prim算法的时间复杂度可以借助二叉堆降低到O(E * logV)。 在这个实现中,我们总是考虑生成树从图的根开始
辅助空间: O(V)

Prim算法的其他实现:

下面给出了 Prim 算法的一些其他实现

  • 用于邻接矩阵表示的 Prim 算法 – 在本文中,我们讨论了在图由邻接矩阵表示的情况下实现 Prim 算法的方法。
  • Prim 的邻接列表表示算法 – 在本文中,Prim 的算法实现针对由邻接列表表示的图进行了描述。
  • 使用优先级队列的 Prim 算法: 在本文中,我们讨论了一种实现 Prim 算法的省时方法。

PRIM算法的优化方法: 

直觉

  1. 我们使用ArrayList<ArrayList<Integer>> 将邻接矩阵转换为邻接列表
  2. 然后我们创建一个 Pair 类来存储顶点及其权重。
  3. 我们根据最低权重对列表进行排序。
  4. 我们创建优先级队列并将第一个顶点及其权重推入队列中
  5. 然后我们遍历它的边并将最小的权重存储在一个名为 ans 的变量中。
  6. 最后,在所有顶点之后,我们返回 ans。

执行

C++

#include<bits/stdc++.h>
using namespace std;
 
typedef pair<int,int> pii;
 
// Function to find sum of weights of edges of the Minimum Spanning Tree.
int spanningTree(int V, int E, int edges[][3])
{  
    // Create an adjacency list representation of the graph
    vector<vector<int>> adj[V];
     
    // Fill the adjacency list with edges and their weights
    for (int i = 0; i < E; i++) {
        int u = edges[i][0];
        int v = edges[i][1];
        int wt = edges[i][2];
        adj[u].push_back({v, wt});
        adj[v].push_back({u, wt});
    }
     
    // Create a priority queue to store edges with their weights
    priority_queue<pii, vector<pii>, greater<pii>> pq;
     
    // Create a visited array to keep track of visited vertices
    vector<bool> visited(V, false);
     
    // Variable to store the result (sum of edge weights)
    int res = 0;
     
    // Start with vertex 0
    pq.push({0, 0});
     
    // Perform Prim's algorithm to find the Minimum Spanning Tree
    while(!pq.empty()){
        auto p = pq.top();
        pq.pop();
         
        int wt = p.first;  // Weight of the edge
        int u = p.second;  // Vertex connected to the edge
         
        if(visited[u] == true){
            continue// Skip if the vertex is already visited
        }
         
        res += wt;  // Add the edge weight to the result
        visited[u] = true// Mark the vertex as visited
         
        // Explore the adjacent vertices
        for(auto v : adj[u]){
            // v[0] represents the vertex and v[1] represents the edge weight
            if(visited[v[0]] == false){
                pq.push({v[1], v[0]});  // Add the adjacent edge to the priority queue
            }
        }
    }
     
    return res;  // Return the sum of edge weights of the Minimum Spanning Tree
}
 
int main()
{
    int graph[][3] = {{0, 1, 5},
                      {1, 2, 3},
                      {0, 2, 1}};
 
    // Function call
    cout << spanningTree(3, 3, graph) << endl;
 
    return 0;
}


            

Java

Python3

输出

4



时间复杂度: O(E*log(E)),其中 E 是边数
辅助空间: O(V^2),其中 V 是顶点数

Prim 寻找最小生成树(MST)的算法:

优点:

  1. Prim 的算法保证在连通的加权图中找到 MST。
  2. 使用二叉堆或斐波那契堆的时间复杂度为 O(E log V),其中 E 是边数,V 是顶点数。
  3. 与其他一些 MST 算法相比,它是一种易于理解和实现的相对简单的算法。

缺点:

  1. 与 Kruskal 算法一样,Prim 算法在具有许多边的密集图上可能会很慢,因为它需要对所有边至少迭代一次。
  2. Prim 的算法依赖于优先级队列,这会占用额外的内存并在非常大的图上减慢算法的速度。
  3. 起始节点的选择会影响 MST 输出,这在某些应用中可能是不可取的。

无论你的目标是考试成功、职业发展,还是纯粹的兴趣,这个数据结构和算法可视化的网站都会是一个无价的资源。

前往这个网站,开始你的学习之旅吧!

这些是常见的:【C语言描述】《数据结构和算法》数据结构JAVA实现 数据结构与算法基础(青岛大学-王卓)数据结构与算法王道数据结构c语言实现 速成数据结构期末考前救急 数据结构视频C语言版教程 数据结构严蔚敏 数据结构郝斌 数据结构考研 JAVA数据结构算法与基础 数据结构王道 2022数据结构学习 数据结构小甲鱼 王卓 学习数据结构 数据结构浙江大学 数据结构复习 数据结构马士兵 数据结构零基础教程 数据结构和算法 数据结构入门 考研数据结构习题讲解 数据结构期末复习 计算机二级