【C++】Prim算法---带权图的最小生成树

Prim算法基本思想用伪代码描述如下:

算法Prim
输入无向连通图G=(V,E)
输出最小生成树T=(U,TE)

1.初始化:U={v};TE={ };
2.重复下述操作直到U=V:
2.1 在E中寻找最短边( i, j ),且满足i∈U,j∈V-U;
2.2 U = U + { j };
2.3 TE = TE + { (i , j) };

以下是Prim算法基于的存储结构
在这里插入图片描述
最小生成树即为:在图的所有生成树中,代价最小的树称为最小生成树。

例题:邻接矩阵为存储结构,实现的无向带权图的最小生成树算法Prim
输入:无向带权连通图
输出:深度遍历、广度遍历、最小生成树
在这里插入图片描述

输入:

请输入两个边顶点的序号:0 1
请输入边的权值:34
请输入两个边顶点的序号:0 2
请输入边的权值:46
请输入两个边顶点的序号:0 5
请输入边的权值:19
请输入两个边顶点的序号:1 4
请输入边的权值:12
请输入两个边顶点的序号:2 3
请输入边的权值:17
请输入两个边顶点的序号:2 5
请输入边的权值:25
请输入两个边顶点的序号:3 4
请输入边的权值:38
请输入两个边顶点的序号:3 5
请输入边的权值:25
请输入两个边顶点的序号:4 5
请输入边的权值:26

输出:

深度优先遍历序列是:ABEDCF
广度优先遍历序列是:ABCFED
最小生成树的生成过程为:
<0,5>19
<5,2>25
<2,3>17
<5,4>26
<4,1>12

示例代码:

#include <iostream>
using namespace std;

const int MaxSize = 10;           //图中最多顶点个数
int visited[MaxSize]={0};
const int MAX = 1000; 

 
struct element			//改进:使用结构体数组代替lowcast数组以及adjvex数组
{
	int lowcost, adjvex;
};

int MinEdge(element *e,int vertexNum);

template <class DataType>
class MGraph
{
public:
	MGraph(DataType a[ ], int n, int e);    //构造函数,建立具有n个顶点e条边的图
	~MGraph( ) { }                     //析构函数为空
	void DFTraverse(int v);              //深度优先遍历图
	void BFTraverse(int v);               //广度优先遍历图
	void Prim(int v)  ;
private:
    DataType vertex[MaxSize];          //存放图中顶点的数组
    int edge[MaxSize][MaxSize];          //存放图中边的数组
    int vertexNum, edgeNum;             //图的顶点数和边数
};

template <class DataType>
MGraph<DataType>::MGraph(DataType a[ ], int n, int e)
{
	int i, j, k ,x;
	vertexNum = n;
	edgeNum = e;
	for (i = 0; i < vertexNum; i++)
		vertex[i] = a[i];
	for (i = 0; i < vertexNum; i++)
		for (j = 0; j < vertexNum; j++)
			edge[i][j] = MAX;
	for (k = 0; k < edgeNum; k++)
	{
		cout << "请输入两个边顶点的序号:";
		cin >> i >> j;			//输入边依附的两个顶点的编号 
		 
		cout << "请输入边的权值:"; 
		cin >> x;
		edge[i][j] = x;		//置边的标志为1 
		edge[j][i] = x;		//无向图 边是相通的 
	}
}

template <class DataType>
void MGraph<DataType>::DFTraverse(int v)
{
	cout << vertex[v];
	visited[v] = 1;
	for (int j = 0; j < vertexNum; j++)
	{
		if (edge[v][j] != MAX && visited[j] == 0)DFTraverse(j); //存在与v相连的j点且j点未被访问过 则进一步遍历j点 
	}
}

template <class DataType>
void MGraph<DataType>::BFTraverse(int v)
{
	int w, j, Q[MaxSize];
	int front = -1, rear = -1;
	cout << vertex[v];
	visited[v] = 1;
	Q[++rear] = v;		//v点入队 
	while (front != rear)
	{
		w = Q[++front];	//Q出队值 w 
		for (j = 0; j < vertexNum; j++)//遍历所有可能与w相连的点 若有,则输出、标记、入队 
		{
			if (edge[w][j] != MAX && visited[j] == 0)//存在与w点相连的j点且j点未被访问过 则输出j点值 然后标记j点将j点入队 
			{
				cout << vertex[j];
				visited[j] = 1;
				Q[++rear] = j;
			}
		}
	}
}

template <class DataType>
void MGraph<DataType>::Prim(int v) 	//从顶点v出发 
{
	int i,j,k;
	element e[MaxSize];	//定义出发点结构体,里面包含当前出发点的所有邻点权值 
	for( i = 0;i<vertexNum;i++)
	{
		e[i].adjvex = v;
		e[i].lowcost = edge[v][i];
	}
	e[v].lowcost = 0;
	for(k = 1;k<vertexNum;k++)	//迭代n-1次 因为一开始已经取了一个起点 剩下n-1个 
	{
		j = MinEdge(e,vertexNum);	//找出还未连接的点中距离目前点最近的 
		cout<<"<"<<e[j].adjvex<<","<<j<<">"<<e[j].lowcost<<endl;	//输出j点 
		e[j].lowcost = 0;
		for(i = 0;i<vertexNum;i++)
		{
			if(edge[i][j]<e[i].lowcost)	//寻找j点到各个点比v到各个点路径短的,并替换 
			{
				e[i].lowcost = edge[i][j];	
				e[i].adjvex = j;	//j与i的距离 比v与i的距离近 因此i的最近点换成j 
			}
		}
	}
 } 
 
int MinEdge(element *e,int vertexNum)
{
	int min = MAX; 
	int res;
	for(int i = 0;i<vertexNum;i++)
	{
		if(e[i].lowcost!=0&&(e[i].lowcost<min))
		{
			res = i;
			min = e[i].lowcost 	;
		}
	}
	return res;
}
int main( )
{
	char ch[]={'A','B','C','D','E','F'};
	MGraph<char> MG(ch, 6, 9);
	for (int i=0; i<MaxSize; i++)
		visited[i]=0;
	cout<<"深度优先遍历序列是:";
	MG.DFTraverse(0);
	cout<<endl;
	for (int i=0; i<MaxSize; i++)
		visited[i]=0;
    cout<<"广度优先遍历序列是:";
	MG.BFTraverse(0);
	cout<<endl;
    cout<<"最小生成树的生成过程为:"<<endl;
    MG.Prim(0);
	cout<<endl;
    system("pause");
}

此题中Prim算法构造最小生成树过程中各参数的变化如下
在这里插入图片描述

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值