C++ 最小生成树和最短路径的实现

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

一.生成树的概念

  一个有n个顶点的无向连通图的生成树是一个极小连通图,它含有图中的所有顶点,但只包含构成一棵树的n-1条边。如果在一棵生成树上添加一条边,必定构成一个环,因为这条边使得它依附的那两个顶点之间有了第二条路径。
   如果一个无向图有n个顶点切少于n-1条边,则是非连通图。如果它多于n-1条边,则一定有回路。但是,有n-1条边的图不一定都是连通图。

二.最小生成树的概念

  一个带权连通图无向图G(假定每条边上的权值均大于零)中可能有多棵生成树,每棵生成树中所有边上的权值之和可能不同;图的所有生成树中具有边上的权值之和的树称为图的最小生成树。
  按照定义,n个顶点的连通图的生成树有n个顶点、n-1条边,因此,构造最小生成树的准则有以下几条:

  1. 必须只使用该图中的边来构造最小生成树
  2. 必须使用且仅使用n-1条边来连接图中的n个顶点,生成树一定是连通的
  3. 不能使用产生回路的边
  4. 最小生成树的权值之和是最小的,但一个图的最小生成树不一定是唯一的。

三.实现最小生成树的算法

建立一个图类(采用邻接矩阵的方式存储)

对邻接矩阵的介绍可以查看 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的步骤:

  1. 首先初始化U={v},以v到其它顶点的所有边为候选边。
  2. 然后重复以下步骤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}
步骤:

  1. 初始化图,lowcost[2]最小
    1

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

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

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

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

  6. 选择(1,4)边,结束
    6

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个顶点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值