最小生成树实验

问题

在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树。

请实现最小生成树算法。

解析

Prim算法:

Prim算法又称“加点法”,用于边数较多带权无向连通图
方法:每次找与之连线权值最小的顶点,将该点加入最小生成树集合中
注意:相同权值任选其中一个即可,但是不允许出现闭合回路的情况。
在这里插入图片描述

kruskal(克鲁斯卡尔)算法:

kruskal算法又称“加边法”,用于边数较少的稀疏图
方法:每次找图中权值最小的边,将边连接的两个顶点加入最小生成树集合中
注意:相同权值任选其中一个即可,但是不允许出现闭合回路的情况。
在这里插入图片描述

实现

//定义
#define MAX_SIZE 10
typedef struct node * graphPointer;

typedef struct node {
	int weight;
	int id;
	graphPointer link;
};
//最小生成树——Prim算法
void prim(graphPointer* graph, int vn) {
	int pointSet[MAX_SIZE+1] = {0};//现有点集
	int i, j;
	int w;//代价
	int targetV;//目标点
	int startV; //起始点
	graphPointer temp;

	printf("Prim:\n");
	//从1号点开始
	pointSet[1] = 1;

	for (i = 1; i < vn; i++) {

		w = 10000;//假设每条边的权重均小于10000;
		//找到从现有点集出发的能够以最小代价达到的点
		for (j = 1; j < vn + 1; j++) {
			if (pointSet[j] == 1) {
				temp = graph[j];
				//找到从j出发的能够以最小代价达到的点
				while (temp != NULL) {
					if (temp->weight < w && pointSet[temp->id]!=1) {
						w = temp->weight;
						targetV = temp->id;
						startV = j;
					}
					temp = temp->link;
				}
			}
		}
		pointSet[targetV] = 1;
		printf("%d --- %d\n",startV,targetV);
	}
}

//最小生成树——Kruskal算法
void kruskal(graphPointer* graph, int vn) {

	int i, j, k;
	int w;//代价
	int targetV;//目标点
	int startV; //起始点
	graphPointer temp,ptr1,ptr2,ptr;
	int flag1, flag2;
	
	//初始化树群
	graphPointer* tree = (graphPointer*)malloc(sizeof(graphPointer*)*(vn + 1));
	//因为0号不用,所以多申请一个
	for (i = 1; i < vn + 1; i++) {
		ptr = (graphPointer)malloc(sizeof(node));
		ptr->id = i;
		ptr->link = NULL;
		tree[i] = ptr;
	}
	int trees[MAX_SIZE][MAX_SIZE] = {0};

	for (i = 1; i < vn + 1; i++) {
		trees[i][i] = 1;//自身可达
	}

	printf("Kruskal:\n");
	for (i = 1; i < vn; i++) {
		w = 10000;//假设每条边的权重均小于10000;
		//找到一条不在现有集合中的最小边
		for (j = 1; j < vn + 1; j++) {
			temp = graph[j];
			while (temp != NULL) {
				if (temp->weight <= w) {
					//树群校验
					
					if (trees[j][temp->id] == 1) {
						//存在回路
					}
					else {
						w = temp->weight;
						targetV = temp->id;
						startV = j;
					}
				}
				temp = temp->link;
			}
		}
		//更新树群,先更新代表,再更新可达节点
		for (k = 1; k < MAX_SIZE; k++) {
			if (trees[startV][k]) {
				trees[targetV][k] = 1;
			}
			else if (trees[targetV][k]) {
				trees[startV][k] = 1;
			}
		}
		for (j = 1; j < MAX_SIZE; j++) {
			if (trees[startV][j]) {
				for (k = 1; k < MAX_SIZE; k++) {
					if (trees[targetV][k]) {
						trees[j][k] = 1;
					}
				}
			}
		}
		for (j = 1; j < MAX_SIZE; j++) {
			if (trees[targetV][j]) {
				for (k = 1; k < MAX_SIZE; k++) {
					if (trees[startV][k]) {
						trees[j][k] = 1;
					}
				}
			}
		}
		printf("%d --- %d  %d\n", startV, targetV,w);
	}

}

github源码地址

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值