构造最小生成树——克鲁斯卡尔算法(Kruskal)

构造最小生成树——克鲁斯卡尔算法(Kruskal)

这里的无向网使用链式存储结构——邻接表表示
在这里插入图片描述

#include<iostream>
using namespace std;
#define OK 1
#define ERROR 0
#define FALSE 0
#define TRUE 1
#define MAXNum 100
//定义无穷大
#define  MAXInt 32767
typedef int Status;
//定义顶点数据类型
typedef char VerTexType;
//定义节点权重的类型
typedef int OtherInfo;
//定义边的数据类型
typedef struct ArcNode {
	int adjvex;//该边指向的顶点的位置
	ArcNode* nextarc;//指向下一条边的指针
	OtherInfo info;//与边相关的信息
}ArcNode;
//定义表结点的类型
typedef struct VNode {
	VerTexType data;//顶点信息
	ArcNode* firstarc;//指向第一条依附该顶点的边的指针
}VNode, AdjList[MAXNum];//AdjList是邻接表类型
//图结构的类型
typedef struct {
	AdjList vertices;//邻接表
	int vexnum, arcnum;//图当前顶点数和弧数
}ALGraph;//图的定义
//该函数查找顶点x在图的顶点表中的下标
int LocateVex(ALGraph G, VerTexType x) {
	for (int i = 0; i < G.vexnum; i++) {
		if (G.vertices[i].data == x) {
			return i;
		}
	}
	return -1;
}

//邻接表的创建——无向网
Status createUDN(ALGraph& G) {
	cout << "请输入无向网的总结点的数目和总的边数" << "\n";
	cin >> G.vexnum >> G.arcnum;
	cout << "请输入无向网中的各个顶点" << "\n";
	for (int i = 0; i < G.vexnum; i++)
	{
		cin >> G.vertices[i].data;
		//初始化表头结点的指针域
		G.vertices[i].firstarc = NULL;
	}
	cout << "请输入每条边的信息:(顶点1 顶点2 权重)" << "\n";
	for (int i = 0; i < G.arcnum; i++) {
		VerTexType x, y;
		OtherInfo info;
		cin >> x >> y>>info;
		//查找两个顶点的下标
		int xIndex = LocateVex(G, x);
		int yIndex = LocateVex(G, y);
		//找到这两个顶点的下标之后就可以往firstarc域插入表结点了
		ArcNode* xArcNode = new ArcNode;
		ArcNode* yArcNode = new ArcNode;
		if (xIndex != -1 && yIndex != -1) {
			//在x结点后面插入邻接y结点的信息
			xArcNode->info = info;
			xArcNode->adjvex = yIndex;
			xArcNode->nextarc = G.vertices[xIndex].firstarc;
			G.vertices[xIndex].firstarc = xArcNode;
			//在y结点后面插入邻接x结点的信息
			yArcNode->info = info;
			yArcNode->adjvex = xIndex;
			yArcNode->nextarc = G.vertices[yIndex].firstarc;
			G.vertices[yIndex].firstarc = yArcNode;
		}
		else
		{
			return ERROR;
		}
	}
	return OK;
}

void outPut(ALGraph G) {
	cout << "输出顶点表如下:" << "\n";
	for (int i = 0; i < G.vexnum; i++)
	{
		cout << G.vertices[i].data << " ";
	}
	cout << "\n输入邻接表如下:" << "\n";
	for (int i = 0; i < G.vexnum; i++)
	{
		printf("%c顶点相邻接的顶点为:\n", G.vertices[i].data);
		ArcNode* p = G.vertices[i].firstarc;
		while (p) {
			printf("%c %d ", G.vertices[p->adjvex].data,p->info);
			p = p->nextarc;
		}
		printf("\n");
	}

}
//构造一个边集存储每个边的信息,用一个结构体数组 存储
typedef struct Edge {
	int ivex;
	int jvex;
	OtherInfo info;
}Edge,E[MAXNum];
bool IsHave(E e,int length, int ivex, int jvex) {
	for (int i = 0; i < length; i++)
	{
		bool flag = ((e[i].ivex == ivex) && (e[i].jvex == jvex)) || ((e[i].ivex == jvex) && (e[i].jvex == ivex));
		if (flag)
		{
			return true;
		}
	}
	return false;
}
void prepare(ALGraph G, E &e) {
	//获取所有边的信息存在数组中,数组的长度为G中边的数目
	int k = 0;
	int length = 0;//记录当前e数组的长度
	for (int i = 0; i < G.vexnum; i++)
	{
		//获取G.vertices[i].data的第一个相邻的边的信息
		ArcNode* p = G.vertices[i].firstarc;
		while (p)
		{
			if (!IsHave(e,length,i,p->adjvex))
			{
				e[k].ivex = i;//这条边的一个顶点的下标为i
				e[k].jvex = p->adjvex;//这条边的另一个顶点的下标
				e[k++].info = p->info;
				length++;
			}
			p = p->nextarc;
		}
	}
	cout << "\n未排序的结果为:\n" << "";
	for (int i = 0; i < G.arcnum; i++)
	{
		printf("%d %d %d\n", e[i].ivex, e[i].jvex, e[i].info);
	}
	//将得到的边的数组进行排序,可以选择时间复杂度小的
	//我这里就用最简单的了
	for (int i = 0; i < (G.arcnum-1); i++)
	{
		int min = i;
		//选出从i开始的最小的那个与i位置上的进行交换
		for (int j = i+1; j < G.arcnum; j++)
		{
			if (e[min].info>e[j].info)
			{
				min = j;
			}
		}
		//交换
		Edge temp = e[min];
		e[min] = e[i];
		e[i] = temp;
	}
	//打印输出,查看排序是否正确
	cout << "\n排序的结果为:\n" << "";
	for (int i = 0; i < G.arcnum; i++)
	{
		printf("%d %d %d\n", e[i].ivex, e[i].jvex, e[i].info);
	}
}


void Kruskal(ALGraph G,ALGraph &minTree,E e) {
	//要维护一个顶点集,如果一天边的两个顶点都被选中过
	//则说明这条边加入之后会形成环,不能加入
	int num = G.vexnum;
	bool* vexBool = new bool[num];
	for (int i = 0; i < num; i++)
	{
		vexBool[i] = false;//表明所有下标的顶点均未被选中
	}
	while (minTree.arcnum<(G.vexnum-1))
	{
		Edge min{};
		min.info = MAXInt;
		for (int i = 0; i < G.arcnum; i++)
		{
			//一条边的两个顶点至少有一个未被选中过
			if ((!vexBool[e[i].ivex])||(!vexBool[e[i].jvex]))
			{
				if (min.info > e[i].info) {
					min = e[i];
				}
			}
		}
		//找到权值最小的一个边min
		//新建一个边结点
		ArcNode* p=new ArcNode;
		p->adjvex = min.jvex;
		p->info = min.info;
		//插入到下标为min.ivex的结点后
		p->nextarc = minTree.vertices[min.ivex].firstarc;
		minTree.vertices[min.ivex].firstarc = p;
		//另一个结点也同理
		ArcNode* q = new ArcNode;
		q->adjvex = min.ivex;
		q->info = min.info;
		//插入到下标为min.ivex的结点后
		q->nextarc = minTree.vertices[min.jvex].firstarc;
		minTree.vertices[min.jvex].firstarc = q;
		//将min.jvex和min.ivex;打上标记
		vexBool[min.ivex] = true;
		vexBool[min.jvex] = true;
		minTree.arcnum++;
	}

}

int main() {
	ALGraph G;
	createUDN(G);
	//输出该图进行查看,是否正确
	outPut(G);
	E e;
	prepare(G, e);
	//初始化只有n个顶点而无边的非连通图
	ALGraph minTree;
	minTree.vexnum = G.vexnum;//两者顶点数相同
	minTree.arcnum = 0;
	for (int i = 0; i < G.vexnum; i++) {
		minTree.vertices[i] = G.vertices[i];
		minTree.vertices[i].firstarc = NULL;
	}
	Kruskal(G, minTree, e);
	outPut(minTree);
	return 0;
}

测试样例:
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜菜iwi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值