最小生成树: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. [转]Activemq管理和基本介绍

    1.ActiveMQ服务器工作模型       通过ActiveMQ消息服务交换消息.消息生产者将消息发送至消息服务,消息消费者则从消息服务接收这些消息.这些消息传送操作是使用一组实现 ActiveM ...

  2. 【转】V4L2+swscale+X264+live555实现流媒体服务端

    写这边博客,一方面是因为自己在做项目的时候不太做笔记,怕以后自己忘记了.另一方面,是让正在寻求资料的同行少走一点弯路吧.不能说我这个方案怎么的好,至少是有一点参考价值的.这边博客需要一定基础才能看明白 ...

  3. autoprefixer安装或者里sass的$mixin处理浏览器前缀

    Autoprefixer是一个后处理程序,不象Sass以及Stylus之类的预处理器.它适用于普通的CSS,可以实现css3代码自动补全.也可以轻松跟Sass,LESS及Stylus集成,在CSS编译 ...

  4. oracle 库文件解决的方法 bad ELF interpreter: No such file or directory

    今天是2014-05-27,今天遇到一个lib问题,再次记录一下.这是一个案例,更是一种解决该问题的方法过程. 当我们在使用sqlplus 登陆unix数据库的时候,有可能出现类似:xxxxxx ba ...

  5. drupal 7.23 上传中文命名文件bug

    $file->filename = trim(drupal_basename($_FILES['files']['name'][$source]), '.'); //在此行下 添加以下代码即可( ...

  6. bach cello

    http://bachlb.blog.163.com/blog/static/1819105120073275251223 一个偶然的机会,卡萨尔斯的父亲来巴塞罗那看卡萨尔斯,并且一起去逛了一间海边的 ...

  7. OC——网络解析获取图片的应用

    headimageView=[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, DEVW, DEVW/2)]; headimageView.cont ...

  8. Win7 64位系统上配置使用32位的Eclipse(转)

    Win7 64位系统上配置使用32位的Eclipse 博客分类: Eclipse eclipse  最近工作电脑换成了64位的win7系统,之前个人电脑上安装的jdk和Eclipse都是32位的.而新 ...

  9. Java-----判断是否为基本类型

    转载自:http://blog.csdn.net/hekewangzi/article/details/51969774

  10. OpenRisc-40-or1200的MMU模块分析

    引言 MMU(memory management unit),无论对于computer architecture designer还是OS designer,都是至关重要的部分,设计和使用的好坏,对性 ...