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语言实现扫雷游戏(初级版)

    C语言实现扫雷游戏(初级版)完整攻略 一、简介 扫雷游戏是一款经典的休闲小游戏,由于其简单易懂、容易上手的特点,受到了很多人的喜爱。本文将详细讲解如何使用C语言实现扫雷游戏的初级版。 二、准备工作 在开始编写代码之前,我们需要安装一个C语言编译器。这里推荐使用gcc编译器,在Linux和MacOS系统上可以直接使用,如果是Windows系统则需要先安装Cyg…

    C 2023年5月23日
    00
  • Java 多层嵌套JSON类型数据全面解析

    Java 多层嵌套JSON类型数据全面解析 什么是JSON JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于人阅读和编写,也易于机器解析和生成。JSON是一种完全独立于语言的数据交换格式,但是在实际应用中,JSON常常以字符串的形式进行传输。 解析JSON 在Java中要解析JSON,可以使用Jackson或者…

    C 2023年5月23日
    00
  • vbscript,jscript脚本编程教学(1)

    VBScript和JScript脚本编程教学(1) 介绍 VBScript和JScript是微软公司开发的脚本语言,它们的语法和使用方法与JavaScript非常相似。VBScript一般被用于ASP.NET网站的开发,而JScript则一般被用于Windows脚本和Windows PowerShell等环境中。 本教程将重点讲解VBScript和JScri…

    C 2023年5月23日
    00
  • 怎么解决外接程序VMDebugger未能加载或导致了异常?

    当我们在使用外接程序 VMDebugger 时,有时候可能会遇到 loading 或者异常的问题,这可能是由于以下几种原因导致的: VMDebugger 路径或者名称错误 VMDebugger 版本不兼容当前系统 VMDebugger 与程序运行时发生冲突 网络问题或者其他异常原因 针对以上问题,我们可以采取以下几种方式进行排查和解决: 1. 确认 VMDe…

    C 2023年5月22日
    00
  • Linux下如何用GCC编译动态库

    Linux下如何用GCC编译动态库 1. 准备工作 在开始编译动态库之前,需要先安装GCC。如果还没有安装,可以使用以下命令进行安装: sudo apt-get install build-essential 此外,编译动态库还需要用到以下两个选项: -shared:将目标文件编译为共享库 -fPIC:编译时生成位置无关代码 2. 编译动态库 下面是编译动态…

    C 2023年5月23日
    00
  • 利用C++11原子量如何实现自旋锁详解

    当多个线程需要访问某个公共资源时,为了避免数据竞争(Data Race)和死锁(Lock),我们通常使用线程同步机制,其中自旋锁(SpinLock)就是其中一种。自旋锁是基于忙等待的一种锁,当一个线程在持有锁的时候,其他线程将会不停地“自旋”,也就是反复检查是否可以获得锁。在这种情况下,当前线程将会占用CPU时间片,从而耗费CPU的计算资源。 使用C++11…

    C 2023年5月23日
    00
  • win7系统开机搜狗应用程序错误(0xc0000409)导致电脑死机

    问题描述 有用户反馈在使用 Win7 系统开机时,出现搜狗应用程序错误(0xc0000409)导致电脑死机的问题。为了解决这个问题,下面是一个完整攻略。 步骤一:删除搜狗输入法 由于问题是由搜狗应用程序引起的,我们可以尝试卸载搜狗输入法以解决问题。具体步骤如下: 点击桌面左下角 Windows 图标,打开“控制面板”。 在“控制面板”页面中,选择“程序”。 …

    C 2023年5月23日
    00
  • 用C编写一个送给女朋友的情人节小程序 可爱!

    下面是“用C编写一个送给女朋友的情人节小程序 可爱!”的完整攻略: 目录 情人节小程序的设计思路 需要用到的C语言知识点 编写情人节小程序的步骤 示例说明 总结 情人节小程序的设计思路 情人节小程序是一款可爱的程序,旨在表达爱意。程序设计的主要部分是一个心形的图案,图案中有两个小人围绕一个爱心旋转,表示两个人相互依存,互相照顾,不离不弃的爱情。同时,程序还会…

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