有向图中获取所有联通分量

本文介绍了如何在有向图中高效地获取所有联通分量,使用简化版的并查集算法,通过Java实现。通过遍历边并更新节点的聚合关系,最后得到每个联通分量的大小,但无法直接获取联通关系的详细信息。若需详细联通关系,建议使用DFS算法,但其时间复杂度较高。
摘要由CSDN通过智能技术生成

有向图中获取所有联通分量

业务需求

在这里插入图片描述

某个无向图如上,我们的目的是找出所有联通分量,如上图中有两个联通分量,可以看成是两张子网。

并查集(Union-Find-Set)

参考博客:
并查集——求无向图的所有连通子图_wangyibo0201的博客-CSDN博客_连通子图

时间复杂度O(S),相比原博客,笔者做出了一些定制版的改变,简化了算法步骤,性能也有所提高。

在这里插入图片描述

以上图为例,我们能够拿到的资源,应该是一条条具备连接关系的线,遍历所有线(无序),形成具有聚合关系的集合,规则如下:

  • 一条边有两个节点,选择一条边任意一个节点编号当做这条边上两个节点的组号;
  • 如果集合中已经有了节点的组号,那么选择集合中的,如果没有,则按照上面规则选择节点组号;
  • 如果一条边两个节点都已经有了组号,那么就将集合中两个组号变为其中一个组号

对于上述的图,我们首先拿到一条条的线,然后扫描进行上述操作:
定义一个集合,存储节点的聚合关系。

  • c1 - c2: 两个节点都没有组号,任意一个节点作为组号
    {(c1,c2),(c2,c2)}
  • b1 - b2: 两个节点都没有组号,任意一个节点作为组号
    {(c1,c2),(c2,c2),(b1,b2),(b2,b2)}
  • c3 - c2: c2具有组号,那么c3与c2在同组c2
    {(c1,c2),(c2,c2),(b1,b2),(b2,b2),(c3,c2)}
  • c4 - c1: c1具有组号,那么c4与c1在同组c2
    {(c1,c2),(c2,c2),(b1,b2),(b2,b2),(c3,c2)(c4,c2)}
  • b3 - b2: b2具有组号,那么b3与b2在同组b2
    {(c1,c2),(c2,c2),(b1,b2),(b2,b2),(b3,b2),(c3,c2)(c4,c2)}

在原生并查集算法中,分步骤计算,第一次字典操作中,存在多个相同key的情况,所以无法使用map的数据结构进行计算,增加了编程实现的难度,且对于非map的数据结构,查询操作的时间复杂度并不低。

而我们这里讨论的算法模型,则可以使用map实现(更推荐各位以map为底层新写一个方便业务处理的数据结构)我们分析上面的步骤,使用map,那么三个基本操作get,put,foreach就能实现上面的所有步骤。

最终得到集合,抽象为关系图:
在这里插入图片描述

上面的情景过于简单,现在增加几个点,形成更复杂的情况:
在这里插入图片描述

同样进行遍历线时,相比上文多了两条线:

  • c5 - c6:两个节点都没有出现过,任意节点当组号
    {(c1,c2),(c2,c2),(b1,b2),(b2,b2),(b3,b2),(c3,c2)(c4,c2),(c5,c5),c6,c5)}
  • c1 - c6:c1与c6都有各自的组号,那么它们同属于一组,
    取出c6的组号c5,将集合中的组号c5全部更换为c1的组号c2
    ​ {(c1,c2),(c2,c2),(b1,b2),(b2,b2),(b3,b2),(c3,c2)(c4,c2),(c5,c2),c6,c2)}

在遍历取出组号的操作时,还可以对组号进行一个记录,即c2:4个,c5:2个,b2,3个 那么我们将节点更少的组号c5改成c2, 而不是反过来,保证需要修改组号的,永远都是一个小子网,如此提高时间复杂度。

最终得到的集合,抽象为关系图:
在这里插入图片描述

代码实现

代码实现,有资源如下:
在这里插入图片描述

java实现:

package caculateTrain;

import lombok.Data;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Wyhao
 * @date 2021/7/13
 **/
public class UnionFindSetTest {
   

    @Test
    public void test() {
   
        ArrayList<NetworkElement> networkElements = new ArrayList<>();
        networkElements.add(new NetworkElement("1", "5", UUID.randomUUID().toString()));
        networkElements.add(new NetworkElement(<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值