最小生成树简单实现(Prim算法与Kruskal算法)

最小生成树简述:

最小生成树(Minimum Spanning Tree)指,在一个有权图中寻找最小权值和的树来连通所有顶点。

Prim算法简述及准备:

Prim的思路很简单,设定一个初始点(列如V0),寻找从此连接的最小的权值的边,然后开始一起比较下一个点出去的所有边的权值,最终得到最小权值的连通所有点的边的最小生成树。

需要一个邻接矩阵表示的图来用于算法的实现:

typedef char VertexType;        //顶点类型 ,默认为char
typedef int EdgeType;              //边的权值  默认int
#define MAXVERTEX 10          //最大的顶点数    默认为10
#define INFINITY 65535              //表示无尽∞
//邻接矩阵的结构
struct MGraph
{
	VertexType vexs[MAXVERTEX];     //顶点数组
	EdgeType arc[MAXVERTEX][MAXVERTEX];    //邻接矩阵  即边数组
	int vertexNum;            //顶点数
	int edgeNum;                 //边数
};

Prim最小生成树:

C++实现:

//Prim最小生成树
void PrimMinSpanTree(MGraph G)
{
	int i, j, k;       //i,j用于循环,k用于存储找到的最小权值顶点下标
	int min;       //min用于存储最小权值来进行比较
	//初始化用于存储的数组
	int adjVertex[MAXVERTEX];       //AdjVertex数组存储边的邻接点
	int lowWeight[MAXVERTEX];       //lowWeight数组存储低权值边
	lowWeight[0] = 0;               //把lowWeight的0下标值设为0,表示0下标顶点V0已经在最小生成树中
	adjVertex[0] = 0;
	for (i = 1; i < G.vertexNum; i++) //从V1开始遍历,遍历邻接矩阵的第一行,即V0到与其相连的边的权值
	{
		lowWeight[i] = G.arc[0][i];        //把有权值的放入lowWeight数组,没有权值的默认为INFINITY
		adjVertex[i] = 0;                 //把adjVertex数组都初始化为0
	}
	//最小生成树
	for (i = 1; i < G.vertexNum; i++)
	{
		min = INFINITY;          //先把min设为一个不可能的值
		j = 1; k = 0;
		while (j<G.vertexNum)         //循环遍历lowWeight
		{
			if (lowWeight[j] !=0 && lowWeight[j]<min)    //lowWeight为0表示该点已经在最小生成树中
			{
				//寻找lowWeight数组最小的值,并记录下标
				min = lowWeight[j];       
				k = j;
			}
			j++;
		}
		//寻找到最小的权值边,开始打印
		cout << "(" << adjVertex[k] << "," << k << ")" << endl;    //输出找到的边
		lowWeight[k] = 0;               //把lowWeight找到的点的下标值设为0,不再参与后面循环
		//改变lowWeight数组,将邻接矩阵第二行的值按条件放入数组用于下次循环
		for (j = 1; j < G.vertexNum; j++)
		{
			if (lowWeight[j] != 0 && G.arc[k][j]<lowWeight[j])
			{
				lowWeight[j] = G.arc[k][j];       //把邻接矩阵第二行更小的数放入lowWeight数组,已经在树内的数除外
				adjVertex[j] = k;                //存储邻接点
			}
		}
	}
}
Prim算法主要是嵌套循环,所以其时间复杂度为O(n^2)。

Kruskal算法简述及准备:

Kruskal算法不再从某一个顶点开始不断遍历寻找,而是优先找较小的权值,然后从最小权值的边进行构造最小生成树。

需要一个图的边集数组来进行

//边集数组结构
struct GraphEdge
{
	VertexType begin;
	VertexType end;
	int weight;
};

Kruskal算法:

int Find(int *parent,int e);
//Kruskal最小生成树
void KruskalMinSpanTree(MGraph G)
{
	int i;        //用于遍历
	int n, m;       //用于判断
	GraphEdge edges[MAXVERTEX];          //边集数组    按从小到大排列
	int parent[MAXVERTEX];             //parent用于判断边是否形成了回路
	for (i = 0; i < G.vertexNum; i++)
	{
		parent[i] = 0;           //初始化parent数组全部为0
	}
	//遍历每一条边
	for (i = 0; i < G.vertexNum; i++)
	{
		n = Find(parent, edges[i].begin);
		m = Find(parent, edges[i].end);
		if (n!=m)        //n != m   说明没有形成闭合回路
		{
			parent[n] = m;
			cout << "(" << edges[i].begin << "," << edges[i].end << ")" << edges[i].weight<<endl;
		}
	}
}

int Find(int *parent, int e)
{
	while (parent[e]>0)
	{
		e = parent[e];
	}
	return e;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值