java 无向图子图_如何查找无向图的所有连接子图

b45c20fe2275e95d9bf760627f2b6c65.png

慕的地10843

这是一个不使用游标,但使用单个递归查询的变体。本质上,它将数据视为图形中的边并递归遍历图形的所有边,并在检测到循环时停止。然后,将所有找到的循环放入组中,并为每个组分配一个数字。请参阅下面有关其工作原理的详细说明。我建议您按CTE逐个运行查询,并检查每个中间结果以了解其作用。样品1DECLARE @T TABLE (ID int, Ident1 char(1), Ident2 char(1));INSERT INTO @T (ID, Ident1, Ident2) VALUES(1, 'a', 'a'),(2, 'b', 'b'),(3, 'c', 'a'),(4, 'c', 'b'),(5, 'c', 'c');样品2我又添加了一行带有z值的行,以使多行具有未配对的值。DECLARE @T TABLE (ID int, Ident1 char(1), Ident2 char(1));INSERT INTO @T (ID, Ident1, Ident2) VALUES(1, 'a', 'a'),(1, 'a', 'c'),(2, 'b', 'f'),(3, 'a', 'g'),(4, 'c', 'h'),(5, 'b', 'j'),(6, 'd', 'f'),(7, 'e', 'k'),(8, 'i', NULL),(88, 'z', 'z'),(9, 'l', 'h');样品3DECLARE @T TABLE (ID int, Ident1 char(1), Ident2 char(1));INSERT INTO @T (ID, Ident1, Ident2) VALUES(1, 'a', 'f'),(2, 'a', 'g'),(3, 'a', NULL),(4, 'b', 'c'),(5, 'b', 'a'),(6, 'b', 'h'),(7, 'b', 'j'),(8, 'b', NULL),(9, 'b', NULL),(10, 'b', 'g'),(11, 'c', 'k'),(12, 'c', 'b'),(13, 'd', 'l'),(14, 'd', 'f'),(15, 'd', 'g'),(16, 'd', 'm'),(17, 'd', 'a'),(18, 'd', NULL),(19, 'd', 'a'),(20, 'e', 'c'),(21, 'e', 'b'),(22, 'e', NULL);询问WITHCTE_IdentsAS(    SELECT Ident1 AS Ident    FROM @T    UNION    SELECT Ident2 AS Ident    FROM @T),CTE_PairsAS(    SELECT Ident1, Ident2    FROM @T    WHERE Ident1 <> Ident2    UNION    SELECT Ident2 AS Ident1, Ident1 AS Ident2    FROM @T    WHERE Ident1 <> Ident2),CTE_RecursiveAS(    SELECT        CAST(CTE_Idents.Ident AS varchar(8000)) AS AnchorIdent         , Ident1        , Ident2        , CAST(',' + Ident1 + ',' + Ident2 + ',' AS varchar(8000)) AS IdentPath        , 1 AS Lvl    FROM         CTE_Pairs        INNER JOIN CTE_Idents ON CTE_Idents.Ident = CTE_Pairs.Ident1    UNION ALL    SELECT         CTE_Recursive.AnchorIdent         , CTE_Pairs.Ident1        , CTE_Pairs.Ident2        , CAST(CTE_Recursive.IdentPath + CTE_Pairs.Ident2 + ',' AS varchar(8000)) AS IdentPath        , CTE_Recursive.Lvl + 1 AS Lvl    FROM        CTE_Pairs        INNER JOIN CTE_Recursive ON CTE_Recursive.Ident2 = CTE_Pairs.Ident1    WHERE        CTE_Recursive.IdentPath NOT LIKE CAST('%,' + CTE_Pairs.Ident2 + ',%' AS varchar(8000))),CTE_RecursionResultAS(    SELECT AnchorIdent, Ident1, Ident2    FROM CTE_Recursive),CTE_CleanResultAS(    SELECT AnchorIdent, Ident1 AS Ident    FROM CTE_RecursionResult    UNION    SELECT AnchorIdent, Ident2 AS Ident    FROM CTE_RecursionResult)SELECT    CTE_Idents.Ident    ,CASE WHEN CA_Data.XML_Value IS NULL     THEN CTE_Idents.Ident ELSE CA_Data.XML_Value END AS GroupMembers    ,DENSE_RANK() OVER(ORDER BY         CASE WHEN CA_Data.XML_Value IS NULL         THEN CTE_Idents.Ident ELSE CA_Data.XML_Value END    ) AS GroupIDFROM    CTE_Idents    CROSS APPLY    (        SELECT CTE_CleanResult.Ident+','        FROM CTE_CleanResult        WHERE CTE_CleanResult.AnchorIdent = CTE_Idents.Ident        ORDER BY CTE_CleanResult.Ident FOR XML PATH(''), TYPE    ) AS CA_XML(XML_Value)    CROSS APPLY    (        SELECT CA_XML.XML_Value.value('.', 'NVARCHAR(MAX)')    ) AS CA_Data(XML_Value)WHERE    CTE_Idents.Ident IS NOT NULLORDER BY Ident;结果1+-------+--------------+---------+| Ident | GroupMembers | GroupID |+-------+--------------+---------+| a     | a,b,c,       |       1 || b     | a,b,c,       |       1 || c     | a,b,c,       |       1 |+-------+--------------+---------+结果2+-------+--------------+---------+| Ident | GroupMembers | GroupID |+-------+--------------+---------+| a     | a,c,g,h,l,   |       1 || b     | b,d,f,j,     |       2 || c     | a,c,g,h,l,   |       1 || d     | b,d,f,j,     |       2 || e     | e,k,         |       3 || f     | b,d,f,j,     |       2 || g     | a,c,g,h,l,   |       1 || h     | a,c,g,h,l,   |       1 || i     | i            |       4 || j     | b,d,f,j,     |       2 || k     | e,k,         |       3 || l     | a,c,g,h,l,   |       1 || z     | z            |       5 |+-------+--------------+---------+结果3+-------+--------------------------+---------+| Ident |       GroupMembers       | GroupID |+-------+--------------------------+---------+| a     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || b     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || c     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || d     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || e     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || f     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || g     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || h     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || j     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || k     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || l     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 || m     | a,b,c,d,e,f,g,h,j,k,l,m, |       1 |+-------+--------------------------+---------+怎么运行的我将使用第二组示例数据进行解释。CTE_IdentsCTE_Idents给出同时出现在Ident1和Ident2列中的所有标识符的列表。由于它们可以按任何顺序出现,因此我们将UNION这两列一起列出。UNION也会删除所有重复项。+-------+| Ident |+-------+| NULL  || a     || b     || c     || d     || e     || f     || g     || h     || i     || j     || k     || l     || z     |+-------+CTE_PairsCTE_Pairs给出两个方向上图形所有边缘的列表。同样,UNION用于删除任何重复项。+--------+--------+| Ident1 | Ident2 |+--------+--------+| a      | c      || a      | g      || b      | f      || b      | j      || c      | a      || c      | h      || d      | f      || e      | k      || f      | b      || f      | d      || g      | a      || h      | c      || h      | l      || j      | b      || k      | e      || l      | h      |+--------+--------+CTE_RecursiveCTE_Recursive是查询的主要部分,它从每个唯一的标识符开始递归遍历图。这些起始行由的第一部分产生UNION ALL。的第二部分以UNION ALL递归方式连接到本身,并链接Ident2到Ident1。由于我们预先制作CTE_Pairs了沿两个方向书写的所有边线,因此我们始终只能链接Ident2到,Ident1并在图中获得所有路径。同时,查询将生成IdentPath-到目前为止已遍历的字符串,以逗号分隔。它用于WHERE过滤器中:CTE_Recursive.IdentPath NOT LIKE CAST('%,' + CTE_Pairs.Ident2 + ',%' AS varchar(8000))一旦我们遇到之前包含在Path中的Identifier,随着连接节点列表的耗尽,递归就会停止。 AnchorIdent是递归的起始标识符,以后将用于对结果进行分组。 Lvl并没有真正使用过,我将其包括在内是为了更好地了解发生了什么。+-------------+--------+--------+-------------+-----+| AnchorIdent | Ident1 | Ident2 |  IdentPath  | Lvl |+-------------+--------+--------+-------------+-----+| a           | a      | c      | ,a,c,       |   1 || a           | a      | g      | ,a,g,       |   1 || b           | b      | f      | ,b,f,       |   1 || b           | b      | j      | ,b,j,       |   1 || c           | c      | a      | ,c,a,       |   1 || c           | c      | h      | ,c,h,       |   1 || d           | d      | f      | ,d,f,       |   1 || e           | e      | k      | ,e,k,       |   1 || f           | f      | b      | ,f,b,       |   1 || f           | f      | d      | ,f,d,       |   1 || g           | g      | a      | ,g,a,       |   1 || h           | h      | c      | ,h,c,       |   1 || h           | h      | l      | ,h,l,       |   1 || j           | j      | b      | ,j,b,       |   1 || k           | k      | e      | ,k,e,       |   1 || l           | l      | h      | ,l,h,       |   1 || l           | h      | c      | ,l,h,c,     |   2 || l           | c      | a      | ,l,h,c,a,   |   3 || l           | a      | g      | ,l,h,c,a,g, |   4 || j           | b      | f      | ,j,b,f,     |   2 || j           | f      | d      | ,j,b,f,d,   |   3 || h           | c      | a      | ,h,c,a,     |   2 || h           | a      | g      | ,h,c,a,g,   |   3 || g           | a      | c      | ,g,a,c,     |   2 || g           | c      | h      | ,g,a,c,h,   |   3 || g           | h      | l      | ,g,a,c,h,l, |   4 || f           | b      | j      | ,f,b,j,     |   2 || d           | f      | b      | ,d,f,b,     |   2 || d           | b      | j      | ,d,f,b,j,   |   3 || c           | h      | l      | ,c,h,l,     |   2 || c           | a      | g      | ,c,a,g,     |   2 || b           | f      | d      | ,b,f,d,     |   2 || a           | c      | h      | ,a,c,h,     |   2 || a           | h      | l      | ,a,c,h,l,   |   3 |+-------------+--------+--------+-------------+-----+CTE_CleanResultCTE_CleanResult只留下来自的相关部分,CTE_Recursive然后再次合并Ident1和Ident2使用UNION。+-------------+-------+| AnchorIdent | Ident |+-------------+-------+| a           | a     || a           | c     || a           | g     || a           | h     || a           | l     || b           | b     || b           | d     || b           | f     || b           | j     || c           | a     || c           | c     || c           | g     || c           | h     || c           | l     || d           | b     || d           | d     || d           | f     || d           | j     || e           | e     || e           | k     || f           | b     || f           | d     || f           | f     || f           | j     || g           | a     || g           | c     || g           | g     || g           | h     || g           | l     || h           | a     || h           | c     || h           | g     || h           | h     || h           | l     || j           | b     || j           | d     || j           | f     || j           | j     || k           | e     || k           | k     || l           | a     || l           | c     || l           | g     || l           | h     || l           | l     |+-------------+-------+最终选择现在,我们需要Ident为每个构建一个用逗号分隔的字符串AnchorIdent。 CROSS APPLY用FOR XML做它。 DENSE_RANK()计算GroupID每个的数字AnchorIdent。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值