[手撕数据结构] 最小生成树Prime算法与kruskal算法

Prime算法和kruskal算法是两个利用MST性质构造最小生成树的算法,两个算法都比较简单 代码如下 本文依照如下图所示进行测试

Prime算法

加点法 逐步增加生成树中顶点

#include <iostream>
#include<stdlib.h>
using namespace std;
#define MVNum 100      //最大顶点数
#define MAXInt 10086      //极大值
typedef struct Mgraph
{
	char vexs[MVNum];                     //顶点表
	int arcs[MVNum][MVNum];               //邻接矩阵
	int vexnum;               //图的当前点数
	int arcnum;               //图的当前边数
}AMGraph;//Adjacency Matrix Graph

struct edge
{
	char adjvex;//最小边在U中的那个顶点
	int mincost;//最小边上的权值
}closedge[MVNum];//辅助数组

int LocateVex(AMGraph* G, char v)//找到结点V在图G中的位置 即下标
{
	for (int i = 0; i < G->vexnum; i++)
	{
		if (G->vexs[i] == v)
		{
			return i;
		}
	}
	cout << "没找到" << endl;
	return 0;
}
void CreatAMG(AMGraph* G)//邻接矩阵表示法创建无向网
{
	cout << "请输入图的总顶点数与总边数: ";
	cin >> G->vexnum >> G->arcnum;//输入总顶点数 总边数
	cout << "输入点的信息: ";
	for (int i = 0; i < G->vexnum; i++)
	{
		cin >> G->vexs[i];
	}
	for (int i = 0; i < G->vexnum; i++)//初始化
	{
		for (int j = 0; j < G->vexnum; j++)
		{
			G->arcs[i][j] = MAXInt;
		}
	}
	char v1, v2;//相连结点
	int w;//权值
	cout << "输入相连结点及边的权值" << endl;
	for (int k = 0; k < G->arcnum; k++)//构造邻接矩阵
	{
		cin >> v1 >> v2 >> w;//表示v1和v2相连接
		int i = LocateVex(G, v1);
		int j = LocateVex(G, v2);
		G->arcs[i][j] = G->arcs[j][i] = w;
	}
	cout << "邻接矩阵如下" << endl;
	for (int i = 0; i < G->vexnum; i++)
	{
		for (int j = 0; j < G->vexnum; j++)
		{
			cout << G->arcs[i][j] << " ";
		}
		cout << "\n";
	}
	return;
}
int Min(struct edge* closedge, AMGraph* G)
{
	int min = MAXInt;
	int ret = -1;
	for (int i = 0; i < G->vexnum; i++)
	{
		if (closedge[i].mincost != 0 && min > closedge[i].mincost)
		{
			min = closedge[i].mincost;
			ret = i;
		}
	}
	return ret;
}
void miniSpanTree_Prime(AMGraph* G, char u)
{
	/*
	* closedge[i].mincost==0 说明i对应的顶点被加入U
	*/
	int k = LocateVex(G, u);//寻找顶点u在G中的位置(vexs中的下标)
	for (int i = 0; i < G->vexnum; i++)
	{
		if (i != k)
		{
			closedge[i] = { u,G->arcs[k][i] };
		}
	}
	closedge[k].mincost = 0;//初始化 U={u}
	cout << "最小生成树如下" << endl;
	for (int i = 1; i < G->vexnum; i++)
	{
		k = Min(closedge, G);
		char u0 = closedge[k].adjvex;
		char v0 = G->vexs[k];
		cout << u0 << v0;
		closedge[k].mincost = 0;
		for (int j = 0; j < G->vexnum; j++)//更新closedge数组
		{
			if (G->arcs[k][j] < closedge[j].mincost)
				closedge[j] = { G->vexs[k],G->arcs[k][j] };
		}
	}
}
int main()
{
	AMGraph* G = (AMGraph*)malloc(sizeof(AMGraph));
	if (G == NULL)
	{
		cout << "空间不足 创建失败" << endl;
		return 0;
	}
	CreatAMG(G);
	miniSpanTree_Prime(G, 'A');
	return 0;
}

测试结果如下

 Kruskal算法

归并边  代码如下

#include <iostream>
#include<algorithm>
using namespace std;
#define MVNum 100      //最大顶点数
#define MAXInt 10086      //极大值
typedef struct Mgraph
{
	char vexs[MVNum];                     //顶点表
	int arcs[MVNum][MVNum];               //邻接矩阵
	int vexnum;               //图的当前点数
	int arcnum;               //图的当前边数
}AMGraph;//Adjacency Matrix Graph

struct Edge
{
	char head;//最小边在U中的那个顶点
	char tail;//最小边上的权值
	int weight;
}edge[MVNum];//辅助数组

int LocateVex(AMGraph* G, char v)//找到结点V在图G中的位置 即下标
{
	for (int i = 0; i < G->vexnum; i++)
	{
		if (G->vexs[i] == v)
		{
			return i;
		}
	}
	cout << "没找到" << endl;
	return 0;
}
void CreatAMG(AMGraph* G)//邻接矩阵表示法创建无向网
{
	cout << "请输入图的总顶点数与总边数: ";
	cin >> G->vexnum >> G->arcnum;//输入总顶点数 总边数
	cout << "输入点的信息: ";
	for (int i = 0; i < G->vexnum; i++)
	{
		cin >> G->vexs[i];
	}
	for (int i = 0; i < G->vexnum; i++)//初始化
	{
		for (int j = 0; j < G->vexnum; j++)
		{
			G->arcs[i][j] = MAXInt;
		}
	}
	char v1, v2;//相连结点
	int w;//权值
	cout << "输入相连结点及边的权值" << endl;
	for (int k = 0; k < G->arcnum; k++)//构造邻接矩阵
	{
		cin >> v1 >> v2 >> w;//表示v1和v2相连接
		edge[k] = { v1,v2,w };
		int i = LocateVex(G, v1);
		int j = LocateVex(G, v2);
		G->arcs[i][j] = G->arcs[j][i] = w;
	}
	cout << "邻接矩阵如下" << endl;
	for (int i = 0; i < G->vexnum; i++)
	{
		for (int j = 0; j < G->vexnum; j++)
		{
			cout << G->arcs[i][j] << " ";
		}
		cout << "\n";
	}
	return;
}
bool cmp(struct Edge a, struct Edge b)
{
	return a.weight < b.weight;
}
int vexset[MVNum];
void miniSpanTree_Krusal(AMGraph* G, char u)
{
	sort(edge, edge + G->arcnum, cmp);
	for (int i = 0; i < G->vexnum; i++)
	{

		vexset[i] = i;         //各顶点自成连通分量  vexset中值一样的话 说明同属一个连通分量
	}
	for (int i = 0; i < G->arcnum; i++)
	{
		int v1 = LocateVex(G, edge[i].head);
		int v2 = LocateVex(G, edge[i].tail);
		int vs1 = vexset[v1];//获取边所在的连通分量
		int vs2 = vexset[v2];
		if (vs1 != vs2)//如果不属于同一连通分量
		{
			cout << edge[i].head << "--" << edge[i].tail << endl;//输出此边
			for (int j = 0; j < G->vexnum; j++)
			{
				if (vexset[j] == vs2)
				{
					vexset[j] = vs1;//合并两个连通分量
				}
			}
		}
	}
}

int main()
{
	AMGraph* G = (AMGraph*)malloc(sizeof(AMGraph));
	if (G == NULL)
	{
		cout << "空间不足 创建失败" << endl;
		return 0;
	}
	CreatAMG(G);
	cout << "最小生成树如下" << endl;
	miniSpanTree_Krusal(G, 'A');
	return 0;
}

测试结果如下

 Kruskal算法更适合求稀疏网的最小生成树

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值