算法作业一

1实验报告

课程名称 《算法分析与设计》 实验日期 2021年 3月10日 至 2021年3月15日
学生姓名 王浩楠 所在班级 计算机195 学号 2019212212179
实验名称 Prim算法和Kruskal算法构造最小生成树过程及代码
实验地点 同组人员

1.问题
[描述算法问题,首选形式化方式(数学语言),其次才是非形式化方式(日常语言)]
Prim算法构造最小生成树
Kruskal算法构造最小生成树
2.解析
[问题的理解和推导,可用电子版直接在此编写,也可用纸笔推导,拍照嵌入本文档]
Prim算法:将所有点分为两类,树顶点(已经被选入生成树的顶点)和非树顶点(还未被选入生成树的顶点)
任选一个顶点加入树,找出一条边添加到生成树且不能有回路
枚举每一个树顶点到每一个非树顶点所有的边,然后找到最短边加入到生成树。依次,重复操作n-1次,直到将所有顶点都加入生成树中。
在这里插入图片描述
在这里插入图片描述

Kruskal算法:
将图中所有的边取出,放入一个列表中,并按权值由小到大的顺序重新排列
再从列表中按次序每次取出一条边回帖到图中,每回帖一条新边进行一次判断,看图中是否存在着环
如果没有生成环,则此边被选中作为最小生成树的一条边
如果生成环,则此边将被丢弃,继续判断下一条边
直到已选择n-1条边(n为最小生成树顶点数),此时最小生成树已构建完成
![(https://img-blog.csdnimg.cn/20210530101910950.png)
在这里插入图片描述
在这里插入图片描述

3.设计
[核心伪代码]
int Prim(int graph[][MAX], int n)
{
int lowcost[MAX];//lowcost[i]记录以i为终点的边的最小权值,当lowcost[i]=0时表示终点i加入生成树
int mst[MAX];//mst[i]记录对应lowcost[i]的起点,当mst[i]=0时表示起点i加入生成树
int i, j, min, minid, sum = 0;
for (i = 2; i <= n; i++)//默认选择1号节点加入生成树,从2号节点开始初始化
{
lowcost[i] = graph[1][i];//最短距离初始化为其他节点到1号节点的距离
mst[i] = 1;//标记所有节点的起点皆为默认的1号节点
}

mst[1] = 0;// 标记1号节点加入生成树
for (i = 2; i <= n; i++)//n个节点至少需要n-1条边构成最小生成树
{
	min = MAXCOST;
	minid = 0;
	for (j = 2; j <= n; j++)//找满足条件的最小权值边的节点minid 
	{
		if (lowcost[j] < min && lowcost[j] != 0)//边权值较小且不在生成树中
		{
			min = lowcost[j];
			minid = j;
		}
	}
	printf("%c - %c : %d\n", mst[minid] + 'A' - 1, minid + 'A' - 1, min);//输出生成树边的信息:起点,终点,权值
	sum += min;//累加权值
	lowcost[minid] = 0;//标记节点minid加入生成树
	for (j = 2; j <= n; j++)//更新当前节点minid到其他节点的权值
	{
		if (graph[minid][j] < lowcost[j])//发现更小的权值
		{
			lowcost[j] = graph[minid][j];//更新权值信息
			mst[j] = minid;//更新最小权值边的起点
		}
	}
}
return sum;//返回最小权值和

}
void kruskal(Edge E[], int n, int e)
{
int i, j, m1, m2, sn1, sn2, k, sum = 0;
int vset[MAXE];
for (i = 1; i <= n; i++) //初始化辅助数组
vset[i] = i;
k = 1;//表示当前构造最小生成树的第k条边,初值为1
j = 0;//E中边的下标,初值为0
while (k < n)//生成的边数小于n时继续循环
{
m1 = E[j].u;
m2 = E[j].v;//取一条边的两个邻接点
sn1 = vset[m1];
sn2 = vset[m2];
//分别得到两个顶点所属的集合编号
if (sn1 != sn2)//两顶点分属于不同的集合,该边是最小生成树的一条边
{//防止出现闭合回路
printf(“V%d-V%d : %d\n”, m1, m2, E[j].weight);
sum += E[j].weight;
k++; //生成边数增加
if (k >= n)
break;
for (i = 1; i <= n; i++) //两个集合统一编号
if (vset[i] == sn2) //集合编号为sn2的改为sn1
vset[i] = sn1;
}
j++; //扫描下一条边
}
printf(“Total:%d\n”, sum);
}

4.分析
[算法复杂度推导]
Kruskal O(n)
Prim O(n)
5.源码
[github源码地址]
https://github.com/Wanghaonan520/algorithm

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值