最小生成树 邻接表 并查表解决

本文介绍了最小生成树的概念,并详细阐述了如何通过Kruskal算法和邻接表来实现。重点讲解了如何利用并查集判断节点是否属于同一棵树,以及如何合并节点以构建最小生成树。文章提供了完整的代码实现过程。
摘要由CSDN通过智能技术生成

什么是最小生成树

树其实是一种特殊的图,只不过树不会有环的存在。
当面对一幅无向有权图,假如现在要从图中找出一幅子图,该子图以最小的总权值连通所有节点。该如何是好?
在这里插入图片描述
我们要得到的是这样的:
在这里插入图片描述
如何做到呢?

Kruskal算法

图的表示方法:邻接表

江湖人称:加边大法。

1:
我们先将所以的边 按权值大小,从小到大排序。
在这里插入图片描述
2:
我们将图中所有节点都视作一棵棵树,每个树有一个根节点就是他本身
上图有6棵树。

遍历我们排好的边,从上到下。如果发现两节点都位于不同的树就将他们合并成一颗树。直到边数为 N - 1(N为结点的个数)结束。

3:
代码实现发现两节点都位于不同的树就将他们合并成一颗树这句话。

这里我们可以使用并查集的思想。
每一棵树我们选择该树中的根结点代表该树(可以将树理解为一个黑社会,根结点是该黑社会老大,根结点代表此树,黑社会老大代表黑社会)

我们首先声明一个列表,该列表的索引是结点,而索引对应的值是 结点 隶属的黑社会(即那棵树的根结点的值,黑社会老大)。

以上图为例(因为一开始大家都互不相干,自己就是自己的老大):
索引 : 0, 1, 2, 3, 4, 5
值 :[0, 1, 2, 3, 4, 5]

在此我们先弄懂,如何根据上述数组找到一个结点的黑社会老大?

“”“
		参数:tar 	图中的一个结点的值
			 nums	记录老大数组
		返回:该结点对应的集合,并返回该集合代表的结点
”“”
        def find(tar, nums):
            while tar != nums[tar]:
                tar = nums[tar]
            return tar

假如我们的数组是这样的:
索引 : 0, 1, 2, 3, 4, 5
值 :[0, 1, 1, 2, 4, 5]

老大的标准是:索引的值和索引对应的值相同,即为老大,这里的老大有0,1,4,5

现在要找结点3的老大:
首先,访问记录老大数组索引3,对应的值为2,检查一下自己是不是老大,不是。结点3的上级是结点2。(结点2有可能是老大,但也可能只是比结点3高一级,不是老大。出现这种情况的原因:3之前认2为自己老大,之后2又认结点1为老大,那么3的老大已经不是2了,是结点1。)

接着,访问索引2对应的值为1,说明结点2不是老大,然后访问结点1

最后,结点1是老大,然后返回结点1。结点3的老大就是结点1

接着是合并函数的实现:
这里讲述的合并函数是最简单的,可以使用路径压缩算法,进一步优化。

# 假设 结点tar_2 要合并 到结点tar_1中:
def join(tar_1, tar_2, nums):
		nums[tar_2] = tar_1 

是的,直接修改记录老大数组,将 索引结点 tar_2 的值修改为 tar_1 即可。记录tar_2的老大是 tar_1。

有了上两个数组的支持,实现就十分简单了:
遍历排序好的边数组。如果发现边的两个结点,调用 find函数 找到他们的老大,如果发现老大不是同一个人(不隶属于同一个黑社会),记录该边,然后将这两个结点使用join函数合并(右结点的老大变为左结点的老大,(这里仅仅是方便,理论上应该是 人少的黑社会 加入 人多的黑社会))。
直到记录边的数组 >= N - 1 时,就返回边的数组,该树就整

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值