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语言实现循环输入的流程一般包括以下几个步骤: 定义变量 设置循环条件 在循环体内接收输入,并进行相应处理 更新循环条件 结束循环 下面我们通过两条示例进一步说明。 示例1:循环输入数字并求和 #include <stdio.h> int main() { int i = 1; // 初始化变量 int sum = 0; while (i &lt…

    C 2023年5月23日
    00
  • C语言 运算符优先级和关联性

    C语言 运算符优先级和关联性 在C语言中,运算符优先级和关联性是非常重要的概念,它们是决定表达式求值结果的关键因素。本篇文章将详细讲解C语言中运算符优先级和关联性的使用方法。 运算符优先级 运算符优先级决定了表达式中运算符的执行顺序,它们会影响表达式求值结果。C语言中,运算符优先级是按照固定的顺序进行计算。下表展示了C语言中一些常见运算符的优先级,从高到低。…

    C 2023年5月9日
    00
  • Java日常练习题,每天进步一点点(38)

    Java日常练习题,每天进步一点点(38) 题目描述 定义父类People,创建子类VIP,编写一个测试类Test,在测试类里面,创建两个People的对象和两个VIP的对象并赋值,然后分别调用他们的属性与方法 题目思路 本题考察了Java面向对象的三大特性:封装、继承、多态。People作为父类,VIP作为子类,VIP拥有自己的新属性和方法。在测试类中,定…

    C 2023年5月23日
    00
  • 浅谈c++ 预处理器

    当我们在编写C++程序时,我们会使用一些预处理指令来告诉编译器预先处理一些代码,以便让程序更加高效和可维护。C++的预处理器是在编译代码之前执行的,它主要负责处理以 # 开始的预处理指令。在本文中,我将详细介绍C++预处理器及其使用。 什么是C++预处理器 C++预处理器是一种特殊的程序,它可以在编译C++源代码之前进行一些处理。它是由程序员使用 # 开头的…

    C 2023年5月23日
    00
  • 华为Mate 8怎么样 华为Mate8全面评测图解

    华为Mate 8怎么样 华为Mate8全面评测图解 华为Mate 8是华为公司于2015年11月发布的一款大屏旗舰手机。其拥有6英寸的大屏幕、高通骁龙810处理器、4GB RAM、16/32/64GB ROM等高端配置,备受市场关注。下面我们来对这款手机进行全面评测,看看它在各方面的表现如何。 设计和外观 华为Mate8采用了一块6英寸的IPS LCD屏幕,…

    C 2023年5月22日
    00
  • QCY T1C真无线蓝牙耳机怎么样 QCY T1C真无线蓝牙耳机拆解介绍

    QCY T1C真无线蓝牙耳机怎么样? 简介 QCY T1C真无线蓝牙耳机是一款真无线蓝牙耳机,采用蓝牙 5.0 技术,漂亮的外观以及出色的音质,是市场上比较受欢迎的商品之一。 音质 QCY T1C 真无线蓝牙耳机采用了 6mm 真空负压动圈单元,有效实现了卓越的超低频效果。同时,这款耳机还支持 SBC 和 AAC 等高保真音质的编码格式,让你在使用过程中可以…

    C 2023年5月23日
    00
  • R语言基础统计方法图文实例讲解

    R语言基础统计方法图文实例讲解 本文将为读者讲解使用R语言进行基础的统计分析方法,具体包括了数据的读取、数据展示及探索性数据分析(EDA)、t检验、方差分析及线性回归分析。 1. 数据的读取 在R语言中,我们可以使用以下代码读取csv或Excel文件: # 读取csv文件 data <- read.csv("data.csv", h…

    C 2023年5月22日
    00
  • 在Linux系统中使用GDB来调试C/C++程序的方法

    在Linux系统中使用GDB来调试C/C++程序的方法可以分为以下几个步骤: 1. 编译C/C++程序时添加编译选项 为了让程序在调试时保留符号表信息,需要在编译C/C++源代码时添加编译选项 -g。例如: $ gcc -g -o myprog myprog.c 这样编译出来的可执行文件中就包含了符号表信息,可以用于调试。 2. 启动GDB调试器 在终端中输…

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