C++ 最小生成树和最短路径的实现
一.生成树的概念
一个有n个顶点的无向连通图的生成树是一个极小连通图,它含有图中的所有顶点,但只包含构成一棵树的n-1条边。如果在一棵生成树上添加一条边,必定构成一个环,因为这条边使得它依附的那两个顶点之间有了第二条路径。
如果一个无向图有n个顶点切少于n-1条边,则是非连通图。如果它多于n-1条边,则一定有回路。但是,有n-1条边的图不一定都是连通图。
二.最小生成树的概念
一个带权连通图无向图G(假定每条边上的权值均大于零)中可能有多棵生成树,每棵生成树中所有边上的权值之和可能不同;图的所有生成树中具有边上的权值之和的树称为图的最小生成树。
按照定义,n个顶点的连通图的生成树有n个顶点、n-1条边,因此,构造最小生成树的准则有以下几条:
- 必须只使用该图中的边来构造最小生成树
- 必须使用且仅使用n-1条边来连接图中的n个顶点,生成树一定是连通的
- 不能使用产生回路的边
- 最小生成树的权值之和是最小的,但一个图的最小生成树不一定是唯一的。
三.实现最小生成树的算法
建立一个图类(采用邻接矩阵的方式存储)
对邻接矩阵的介绍可以查看 C++ 实现图的存储和遍历
#include <iostream>
using namespace std;
#define MAX 100
#define INF 0x3f3f3f3f
//图的邻接矩阵存储方法
class VertexType{
//顶点类型
public:
int no;
char data[MAX];
};
class MGraph{
//图邻接矩阵类型
public:
int edges[MAX][MAX];
int n,e;
VertexType vexs[MAX];
};
class Edge{
//克鲁斯卡尔求最小生成树需要用到
public:
int u;
int v;
int w;
};
class Graph{
public:
void createMGraph(int a[][MAX],int n,int e);
void prim(int v);
void kruskal();
void dijkstra(int v);
private:
MGraph g;
void sortEdge(Edge E[],int e);
void dispAllPath(int dist[],int path[],int S[],int v,int n);
};
(一)普里姆(Prim)算法
普里姆(Prim)算法是一种构造性算法。假设G=(V,E)是一个具有n个顶点的带权无向连通图,T=(U,TE)是G的最小生成树,其中,U是T的顶点集,TE是T的边集,则由G构造从起始点v出发的最小生成树T的步骤:
- 首先初始化U={v},以v到其它顶点的所有边为候选边。
- 然后重复以下步骤n-1次,使得其它n-1个顶点被加入到U中。
①从候选边中挑选权值最小的边加入TE,设该边在V-U中的顶点是k,将k加入U中;
②考察当前V-U中的所有顶点j,修改侯选边,若(k,j)的权值小于原来和顶点j关联的侯选边,则用(k,j)取代后者作为侯选边。

例:当邻接矩阵为
{0,6,1,5,INF,INF},{6,0,5,INF,3,INF},{1,5,0,5,6,4}
{5,INF,5,0,INF,2},{INF,3,6,INF,0,6},{INF,INF,4,2,6,0}
步骤:
-
初始化图,lowcost[2]最小

-
选择(0,2)边并调整,lowcost[4]最小

-
选择(2,5)边并调整,lowcost[3]最小

-
选择(5,3)边并调整,lowcost[1]最小

-
选择(2,1)边并调整,lowcost[4]最小

-
选择(1,4)边,结束

Prim算法
void Graph::prim(int v){
int lowcost[MAX];
int closest[MAX];
int min,i,j,k;
for(i=0;i<this->g.n;i++){
//置初值
lowcost[i] = this->g.edges[v][i];
closest[i] = v;
}
for(i=1;i<this->g.n;i++){
//找出n-1个顶点

本文介绍了图的生成树和最小生成树概念,阐述构造最小生成树的准则。详细讲解实现最小生成树的普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法,还介绍了最短路径概念,以及求单源最短路径的狄克斯特拉(Dijkstra)算法和求解每对顶点最短路径的弗洛伊德(Floyd)算法。
最低0.47元/天 解锁文章
1575

被折叠的 条评论
为什么被折叠?



