最小生成树:Prim算法

最小生成树

给定一无向带权图。顶点数是n,要使图连通仅仅需n-1条边。若这n-1条边的权值和最小,则称有这n个顶点和n-1条边构成了图的最小生成树(minimum-cost spanning tree)。

Prim算法

Prim算法是解决最小生成树的经常使用算法。

它採取贪心策略,从指定的顶点開始寻找最小权值的邻接点。图G=<V,E>。初始时S={V0}。把与V0相邻接。且边的权值最小的顶点增加到S。

不断地把S中的顶点与V-S中顶点的最小权值边增加,直到全部顶点都已增加到S中。

算法说明

为了方便寻找最小权值的边,构建一近期边结构体CloseEdge:

//近期边
typedef struct closeedge_tag
{
int adjvex; //邻接点
int weight; //权值
}CloseEdge;

创建一数组CloseEdge closeedge[n];顶点u属于S,顶点v属于V-S,则closeedge[v].weight=min{weight(u,v)};closeedge[v].adjvex=u;另外设置一bool型的数组add,标记顶点i是否已增加S。结合closeedge和add就可以得到当前最小权值边。

每当有新的节点增加S时。则需更新closeedge。

详细细节看代码。

实例

从V0開始

代码

类定义

#include<iostream>
#include<iomanip>
#include<stack>
using namespace std;
#define MAXWEIGHT 100
//边
typedef struct edge_tag
{
int tail;
int head;
}Edge;
//近期边
typedef struct closeedge_tag
{
int adjvex; //邻接点
int weight; //权值
}CloseEdge;
class Graph
{
private:
//顶点数
int numV;
//边数
int numE;
//邻接矩阵
int **matrix;
public:
Graph(int numV);
//建图
void createGraph(int numE);
//析构方法
~Graph();
//Prim算法
void Prim(int);
int minEdgeVex(CloseEdge*, bool*);
void updateCloseEdge(CloseEdge*, bool*, int);
//打印邻接矩阵
void printAdjacentMatrix();
//检查输入
bool check(int, int, int);
};

类实现

//构造函数,指定顶点数目
Graph::Graph(int numV)
{
//对输入的顶点数进行检測
while (numV <= 0)
{
cout << "顶点数有误! 又一次输入 ";
cin >> numV;
}
this->numV = numV;
//构建邻接矩阵,并初始化
matrix = new int*[numV];
int i, j;
for (i = 0; i < numV; i++)
matrix[i] = new int[numV];
for (i = 0; i < numV; i++)
for (j = 0; j < numV; j++)
{
if (i == j)
matrix[i][i] = 0;
else
matrix[i][j] = MAXWEIGHT;
}
}
void Graph::createGraph(int numE)
{
/*
对输入的边数做检測
一个numV个顶点的有向图,最多有numV*(numV - 1)条边
*/
while (numE < 0 || numE > numV*(numV - 1))
{
cout << "边数有问题。又一次输入 ";
cin >> numE;
}
this->numE = numE;
int tail, head, weight, i;
i = 0;
cout << "输入每条边的起点(弧尾)、终点(弧头)和权值" << endl;
while (i < numE)
{
cin >> tail >> head >> weight;
while (!check(tail, head, weight))
{
cout << "输入的边不对! 请又一次输入 " << endl;
cin >> tail >> head >> weight;
}
//Prim算法主要针对的是无向图
matrix[tail][head] = weight;
matrix[head][tail] = weight;
i++;
}
}
Graph::~Graph()
{
int i;
for (i = 0; i < numV; i++)
delete[] matrix[i];
delete[]matrix;
}
/*
Prim算法
求最小生成树
*/
void Graph::Prim(int vertex)
{
//有numV个顶点的图的最小生成树有numV-1条边
Edge *edges = new Edge[numV - 1];
//标记顶点是否增加
bool *add = new bool[numV];
memset(add, 0, numV);
//先把vertex增加
add[vertex] = true;
//近期边
CloseEdge *closeedge = new CloseEdge[numV];
int i;
//初始化近期边
for (i = 0; i < numV; i++)
{
closeedge[i].weight = matrix[vertex][i];
if (!add[i] && matrix[vertex][i] > 0 && matrix[vertex][i] < MAXWEIGHT)
closeedge[i].adjvex = vertex;
}
int v, count = 0;
while (count < numV - 1)
{
//获取近期边的邻接点
v = minEdgeVex(closeedge, add);
add[v] = true;
//把最小权值边依次增加数组edges
edges[count].tail = closeedge[v].adjvex;
edges[count].head = v;
//更新近期边
updateCloseEdge(closeedge, add, v);
count++;
}
cout << "从顶点 " << vertex << " 開始。最小生成树的边是" << endl;
for (i = 0; i < count; i++)
cout << edges[i].tail << "---" << edges[i].head << endl;
//释放空间
delete[]edges;
delete[]add;
delete[]closeedge;
}
//从closeedge中寻找最小边的邻接顶点
int Graph::minEdgeVex(CloseEdge *closeedge, bool *add)
{
int i, v, w;
v = 0;
w = MAXWEIGHT;
for (i = 0; i < numV ; i++)
if (!add[i] && closeedge[i].weight < w)
{
w = closeedge[i].weight;
v = i;
}
return v;
}
//顶点v的增加后,须要更新近期边
void Graph::updateCloseEdge(CloseEdge* closeedge, bool *add, int v)
{
int i;
for (i = 0; i < numV; i++)
if (!add[i] && matrix[v][i] < closeedge[i].weight)
{
closeedge[i].adjvex = v;
closeedge[i].weight = matrix[v][i];
}
}
//打印邻接矩阵
void Graph::printAdjacentMatrix()
{
int i, j;
cout.setf(ios::left);
cout << setw(7) << " ";
for (i = 0; i < numV; i++)
cout << setw(7) << i;
cout << endl;
for (i = 0; i < numV; i++)
{
cout << setw(7) << i;
for (j = 0; j < numV; j++)
cout << setw(7) << matrix[i][j];
cout << endl;
}
}
bool Graph::check(int tail, int head, int weight)
{
if ((tail == head) || tail < 0 || tail >= numV
|| head < 0 || head >= numV
|| weight <= 0 || weight >= MAXWEIGHT)
return false;
return true;
}

主函数

int main()
{
cout << "******Prim***by David***" << endl;
int numV, numE;
cout << "建图..." << endl;
cout << "输入顶点数 ";
cin >> numV;
Graph graph(numV);
cout << "输入边数 ";
cin >> numE;
graph.createGraph(numE);
cout << endl << "Prim..." << endl;
/*
因为输出结果太长,不利于截图,故仅仅打印一半的节点
要想获得从全部节点開始的最小生成树,改动i的变化范围就可以
*/
for (int i = 0; i < numV / 2; i++)
graph.Prim(i);
system("pause");
return 0;
}

执行

完整代码下载:Prim算法

转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38377091

若有所帮助。顶一个哦。

专栏文件夹:

版权声明:本文博主原创文章,转载,转载请注明出处。

数据结构:最小生成树--Prim算法的更多相关文章

  1. 数据结构代码整理(线性表,栈,队列,串,二叉树,图的建立和遍历stl,最小生成树prim算法)。。持续更新中。。。

    //归并排序递归方法实现 #include <iostream> #include <cstdio> using namespace std; #define maxn 100 ...

  2. 最小生成树Prim算法(邻接矩阵和邻接表)

    最小生成树,普利姆算法. 简述算法: 先初始化一棵只有一个顶点的树,以这一顶点开始,找到它的最小权值,将这条边上的令一个顶点添加到树中 再从这棵树中的所有顶点中找到一个最小权值(而且权值的另一顶点不属 ...

  3. 最小生成树—prim算法

    最小生成树prim算法实现 所谓生成树,就是n个点之间连成n-1条边的图形.而最小生成树,就是权值(两点间直线的值)之和的最小值. 首先,要用二维数组记录点和权值.如上图所示无向图: int map[ ...

  4. Highways POJ-1751 最小生成树 Prim算法

    Highways POJ-1751 最小生成树 Prim算法 题意 有一个N个城市M条路的无向图,给你N个城市的坐标,然后现在该无向图已经有M条边了,问你还需要添加总长为多少的边能使得该无向图连通.输 ...

  5. SWUST OJ 1075 求最小生成树(Prim算法)

    求最小生成树(Prim算法) 我对提示代码做了简要分析,提示代码大致写了以下几个内容 给了几个基础的工具,邻接表记录图的一个的结构体,记录Prim算法中最近的边的结构体,记录目标边的结构体(始末点,值 ...

  6. 图论算法(五)最小生成树Prim算法

    最小生成树\(Prim\)算法 我们通常求最小生成树有两种常见的算法--\(Prim\)和\(Kruskal\)算法,今天先总结最小生成树概念和比较简单的\(Prim\)算法 Part 1:最小生成树 ...

  7. 最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析

    最小生成树,Prim算法与Kruskal算法,408方向,思路与实现分析 最小生成树,老生常谈了,生活中也总会有各种各样的问题,在这里,我来带你一起分析一下这个算法的思路与实现的方式吧~~ 在考研中呢 ...

  8. 数据结构之最小生成树Prim算法

    普里姆算法介绍 普里姆(Prim)算法,是用来求加权连通图的最小生成树算法 基本思想:对于图G而言,V是所有顶点的集合:现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T存放G的最 ...

  9. 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind

    最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...

随机推荐

  1. 行变列 pivot

    SELECT p.City , [临时] , [会员] , VIPFROM ( SELECT c.CustomerID , c.City , CASE WHEN COUNT(o.OrderID) &l ...

  2. java实现写大量数据到文件中

    生成.txt文件 生成.csv文件 生成.xls文件 import java.io.BufferedWriter; import java.io.File; import java.io.FileOu ...

  3. Oracle基础学习5-- Oracle权限之”角色”

    不论什么与权限相关的东西都少不了"角色"的概念,Java如此,.Net如此,Oracle当然也不例外. 角色事实上就是权限的集合,将多个权限打包到一个角色中,这样每一个角色有特定的 ...

  4. C# 坦克大战学习总结

    1.学会用Resource管理资源 添加资源 在properties下的Resource.resx添加资源 使用资源 工程名.Properties.Resource.资源名 实际本质,是一个流. 2. ...

  5. 搭建高可用mongodb集群—— 分片

    从节点每个上面的数据都是对数据库全量拷贝,从节点压力会不会过大? 数据压力大到机器支撑不了的时候能否做到自动扩展? 在系统早期,数据量还小的时候不会引起太大的问题,但是随着数据量持续增多,后续迟早会出 ...

  6. diffuse linux 文件比对工具

    linux下比较好用的可视化文件比对工具

  7. VLC各个Module模块之间共享变量的实现方法

    在做VLC开发的时候,想使用一个模块访问另外一个模块的数据, 比如在网络模块得到了一些数据,想在其他模块得到这些数据进行处理,这时候就需要两个模块共享一些变量. 查看VLC的源码,发现VLC专门有va ...

  8. 解决 Visual Studio 2012 有时不能调试的问题

    有时候发现 Visual Studio 2012 不能调试,有时候又能调试.感觉很烦,今天找到了一个解决办法,我也不知道为什么这样能解决. 问题: 解决:1. 找到 Properties ,双击 2. ...

  9. C#中“@”的作用和用法

    “@”在看别人程序的时候偶尔看到,总结了一下两个用途 1. 不常用,也不推介用的用法. @关键字 可以作为标识符来使用,说白了,就是讲关键字变成非关键字. 2.逐字字符串字面量,以@开头,后面是由引导 ...

  10. C#面试题总结——程序设计基础

    一.类型与变量 1.C#支持哪几个预定义的值类型? 主要包括五个类型:整数,浮点数,字符型,bool类型以及decimal型(小数型).其中每一个类型分别有多个内置类型组成. 2.C#支持哪几个预定义 ...