C++示例详解Prim算法与优先队列

C++示例详解Prim算法与优先队列

什么是Prim算法?

Prim算法是一种经典的最小生成树算法,它可以用于求无向连通图的最小生成树。该算法以一个顶点开始,通过不断地向外扩张生成最小生成树,最终遍历图中所有节点,并且每次扩张的时候选择权值最小的边。

Prim算法的实现流程

  1. 选取一个起始节点开始。

  2. 初始化辅助数组,该数组用来记录图中每个节点是否已经被访问,以及每个节点与已经访问的节点的最短距离,初始时所有节点都未被访问,距离为正无穷。

  3. 将起始节点标记为已经访问,并设置其与其他节点的距离为0。

  4. 从起始节点开始,遍历与其相连的所有节点,更新其到已访问节点的距离。

  5. 在所有未访问的节点中,选取与已访问节点距离最短的那个节点,标记为已经访问。

  6. 不断重复步骤4和5,直到遍历完图中所有节点。

  7. 最终生成的最小生成树是一个有n-1条边的连通子图,其中n为节点的数量。

用优先队列实现Prim算法

优先队列可以帮助我们快速找到未访问的节点中距离最短的那个节点。具体实现流程如下:

  1. 创建一个优先队列,用来存储还未访问的节点,队列按节点到已访问节点的距离从小到大排序,距离越小越先出队。

  2. 初始化辅助数组,该数组用来记录图中每个节点是否已经被访问,以及每个节点与已经访问的节点的最短距离,初始时所有节点都未被访问,距离为正无穷。

  3. 将起始节点标记为已经访问,并设置其与其他节点的距离为0。

  4. 将起始节点加入优先队列。

  5. 不断执行以下步骤,直到遍历完图中所有节点:

  6. 从优先队列中取出距离最近的节点,并将其标记为已访问。

  7. 遍历该节点的所有邻居节点,更新其与已访问节点的距离。

  8. 如果该邻居节点还没有被访问,将其加入优先队列中。

  9. 最终生成的最小生成树是一个有n-1条边的连通子图,其中n为节点的数量。

示例1

下面是C++示例代码实现,该示例用优先队列实现了Prim算法。

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

const int INF = 0x3f3f3f3f;

int main() {
    int n = 6, m = 9;
    vector<vector<int> > edges = {{0, 1, 3}, {0, 2, 1}, {1, 2, 5}, {1, 3, 4}, {2, 3, 2}, {2, 4, 7}, {3, 4, 6}, {3, 5, 5}, {4, 5, 8}};

    vector<int> dist(n, INF), visited(n, false);
    priority_queue<pair<int, int>, vector<pair<int, int> >, greater<pair<int, int> > > q;

    int start = 0;
    dist[start] = 0;
    q.push(make_pair(0, start));

    int ans = 0;
    while (!q.empty()) {
        auto cur = q.top();
        q.pop();
        int d = cur.first, u = cur.second;
        if (visited[u]) {
            continue;
        }
        visited[u] = true;
        ans += d;

        for (auto edge : edges) {
            if (edge[0] == u) {
                int v = edge[1], w = edge[2];
                if (!visited[v] && w < dist[v]) {
                    dist[v] = w;
                    q.push(make_pair(dist[v], v));
                }
            }
            if (edge[1] == u) {
                int v = edge[0], w = edge[2];
                if (!visited[v] && w < dist[v]) {
                    dist[v] = w;
                    q.push(make_pair(dist[v], v));
                }
            }
        }
    }

    cout << ans << endl;

    return 0;
}

以上代码部分类和变量的含义说明如下:

  • n: 节点的数量。
  • m: 边的数量。
  • edges: 存储图的邻接矩阵。
  • dist: 存储每个节点与已经访问节点的最短距离。
  • visited: 存储每个节点是否已经被访问。
  • q: 优先队列,用来存储还未访问的节点。
  • start: 起始节点。
  • ans: 最小生成树的权值和。

以上代码使用了STL的优先队列实现。时间复杂度为O(E*logE),其中E为图中边的数量。

示例2

下面是C++示例代码实现,该示例用数组实现了Prim算法。

#include <iostream>
#include <vector>
using namespace std;

const int INF = 0x3f3f3f3f;

int main() {
    int n = 6, m = 9;
    vector<vector<int> > edges = {{0, 1, 3}, {0, 2, 1}, {1, 2, 5}, {1, 3, 4}, {2, 3, 2}, {2, 4, 7}, {3, 4, 6}, {3, 5, 5}, {4, 5, 8}};

    vector<int> dist(n, INF), visited(n, false);

    int start = 0;
    dist[start] = 0;

    int ans = 0;
    for (int i = 0; i < n; i++) {
        int u = -1, min_dist = INF;
        for (int j = 0; j < n; j++) {
            if (!visited[j] && dist[j] < min_dist) {
                u = j;
                min_dist = dist[j];
            }
        }
        if (u == -1) {
            break;
        }
        visited[u] = true;
        ans += min_dist;

        for (auto edge : edges) {
            if (edge[0] == u) {
                int v = edge[1], w = edge[2];
                if (!visited[v] && w < dist[v]) {
                    dist[v] = w;
                }
            }
            if (edge[1] == u) {
                int v = edge[0], w = edge[2];
                if (!visited[v] && w < dist[v]) {
                    dist[v] = w;
                }
            }
        }
    }

    cout << ans << endl;

    return 0;
}

以上代码部分类和变量的含义说明如下:

  • n: 节点的数量。
  • m: 边的数量。
  • edges: 存储图的邻接矩阵。
  • dist: 存储每个节点与已经访问节点的最短距离。
  • visited: 存储每个节点是否已经被访问。
  • start: 起始节点。
  • ans: 最小生成树的权值和。

以上代码使用了数组实现,时间复杂度为O(V^2),其中V为节点的数量。

总结

本篇文章详细讲解了Prim算法和用优先队列实现Prim算法的流程。希望读者通过阅读本文,可以对Prim算法有一个全面的认识,并且能够掌握用优先队列实现Prim算法的技能。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++示例详解Prim算法与优先队列 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C++中string使用+号与int拼接方式

    下面我将详细介绍C++中string使用+号与int拼接方式的攻略。 方式一:利用to_string()函数将int转为string类型 C++中,string类型可以通过在字符串后面直接添加“+”操作符的方式与另一个字符串或字符进行拼接,但无法直接与int类型拼接。在这种情况下,我们需要先将int类型转换为string类型,然后再进行拼接。 具体的步骤如下…

    C 2023年5月22日
    00
  • GO语言中通道和sync包的使用教程分享

    GO语言中通道和sync包的使用教程分享 什么是通道 通道(channel)是 Go 语言中一种特有的同步原语,用于在不同 Goroutine 之间交换数据。通道是一种类型的值,可以对它进行初始化、传递给函数、赋值给变量,甚至可以把它放到切片或结构体中。 创建通道 通道通过 make() 函数来创建,语法如下: ch := make(chan int) 这里…

    C 2023年5月23日
    00
  • C语言队列和应用详情

    C 语言队列和应用详情 什么是队列 队列是一种数据结构,可以用来存储一组按顺序排列的元素。队列的特点就是先进先出,即First In First Out,缩写为 FIFO。也就是说,最先插入队列的元素会最先被取出,最后插入队列的元素则会最后被取出。常见的生活中队列应用包括的排队取号,排队坐火车,排队打饭等等。 C 语言实现队列 在 C 语言中,我们可以通过数…

    C 2023年5月23日
    00
  • C语言中基础小问题详细介绍

    C语言中基础小问题详细介绍攻略 在学习C语言的过程中,会遇到一些基础小问题,这些问题虽然看起来不起眼,但它们却是我们在开发过程中需要深入理解和运用的知识点。下面我们将介绍几个基础小问题及其解决方法,希望对您的学习有所帮助。 问题一:如何输出带有引号的字符串? 在C语言中,若要输出带有引号的字符串,可以采用转义字符\。 例如,要输出”hello world”,…

    C 2023年5月23日
    00
  • C++实现STL迭代器萃取的示例代码

    一、什么是迭代器萃取? 迭代器萃取是一种通过编译时模板元编程技术,获取迭代器类型相关信息的方法。例如,获取迭代器的 value_type、iterator_category、difference_type 和 pointer 等信息。通过迭代器萃取,我们可以更加精确地对各种类型的迭代器进行操作,并且提供更高的泛型性和可重用性。 迭代器萃取一般通过 C++ S…

    C 2023年5月24日
    00
  • 电脑开机黑屏错误提示0xc0000e9怎么办?

    电脑开机黑屏错误提示0xc0000e9的解决方法 问题描述 当你从电脑开机时,如果出现了“电脑开机黑屏错误提示0xc0000e9”的错误,那么说明电脑在启动过程中遇到了一些问题,无法正常启动。这时电脑会停在黑屏界面,无论你进行任何操作,都无法进入系统。此时应该如何处理呢? 解决方法 方法一:检查硬件连接 0xc0000e9错误通常是硬件损坏或者连接错误导致的…

    C 2023年5月23日
    00
  • C/C++读写JSON数据的详细过程记录

    C/C++读写JSON数据的详细过程记录 什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于读写和解析,同时也易于机器生成和解析。JSON文本格式在互联网上广泛应用,尤其在Web应用中,如:动态数据的传输。常用于替代XML格式,因为JSON格式更加简洁、易读、易于解析和生成。 读取JSON数据 使…

    C 2023年5月23日
    00
  • C#自动创建数据库实现代码

    要实现C#自动创建数据库的代码,可以采用ADO.NET的方式来实现。以下是实现步骤: 1. 引入命名空间和依赖库 首先,在代码文件中引入命名空间和依赖库 using System.Data.SqlClient; 2. 创建数据库连接 使用SqlConnection类创建数据库连接对象,然后使用连接字符串指定连接的数据库和身份认证信息。 string conn…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部