使用快速查找算法 (Java) 在有向图中查找所有弱连通分量的优化

Posted

技术标签:

【中文标题】使用快速查找算法 (Java) 在有向图中查找所有弱连通分量的优化【英文标题】:Optimization for Find All Weakly Connected Components in Directed Graph Using Quick-Find Algorithm (Java) 【发布时间】:2016-08-17 02:09:16 【问题描述】:

我正在寻求改进我的解决方案,以便使用 Quick-Find 算法在有向图中查找所有弱连通分量。

问题陈述

给定DirectedGraphNode 的列表,找到所有岛屿(即弱连接组件)。

public class DirectedGraphNode 
    String val;
    List<DirectedGraphNode> neighbors;

因此,给定以下有向图:

A —> B —> <— C 
     ^
     |
     E <— F —> D —> G

X -> <- Y

node : neighbors
  A  :  [B]
  B  :  [C, E]
  C  :  [B]
  D  :  [G]
  E  :  []
  F  :  [E, D]
  G  :  []
  X  :  [Y]
  Y  :  [X]

输出应该如下(顺序无关紧要):

[
   [A, B, C, E, D, F, G],
   [X, Y]
]

我使用 快速查找 算法解决了这个问题。代码如下:

public static List<List<Node>> connectedComponents(List<Node> nodes) 
    if (nodes == null || nodes.size() == 0) 
        throw new IllegalArgumentException("List node is empty");
    

    // Maintain array with name for each element
    String[] labels = new String[nodes.size()];
    // Initially, set the labels of each element to itself
    // Use HashMap to memorize the index
    Map<String, Integer> map = new HashMap<>();
    for (int i = 0; i < labels.length; i++) 
        labels[i] = nodes.get(i).val;
        map.put(nodes.get(i).val, i);
    

    for (Node node : nodes) 
        if (node.neighbors == null || node.neighbors.isEmpty()) 
            continue;
        

        int changerIdx = map.get(node.val);
        for (Node nbr : node.neighbors) 
            int changeeIdx = map.get(nbr.val);
            String symbol = labels[changeeIdx];
            for (int i = 0; i < labels.length; i++) 
                if (labels[i] == symbol) 
                    labels[i] = labels[changerIdx];
                
            
        
    
    return createIslandList(labels, nodes);


private static List<List<Node>> createIslandList(String[] labels, List<Node> nodes) 
    List<List<Node>> res = new ArrayList<List<Node>>();
    if (labels == null || labels.length == 0) 
        return res;
    

    Map<String, List<Node>> map = new HashMap<String, List<Node>>();
    for (int i = 0; i < labels.length; i++) 
        if (!map.containsKey(labels[i])) 
            List<Node> island = new ArrayList<>();
            island.add(nodes.get(i));
            map.put(labels[i], island);
         else 
            map.get(labels[i]).add(nodes.get(i));
        
    

    for (String key : map.keySet()) 
        res.add(map.get(key));
    

    return res;

然而,这个算法在最坏的情况下运行在 O(N^3),因为它每次都需要对联合进行线性搜索。我很好奇是否有任何方法可以改善这一点。

感谢您的建议!

【问题讨论】:

我不确定它的性能 jgrapht.org/javadoc/org/jgrapht/alg/ConnectivityInspector.html 来自 JGraphT,所以只是一个提示:“目前,检查器支持无向图的连接组件和有向图的弱连接组件” 【参考方案1】:

这是一个经过编辑的答案。抱歉,我对弱连接组件和强连接组件感到困惑。

确定弱连接组件实际上非常简单。只需将所有边转换为无向并执行 BFS 或 DFS。

运行时间为O(|V| + |E|),其中V 是顶点集,E 是边集。

【讨论】:

Java 实现:jgrapht.org/javadoc/org/jgrapht/alg/package-summary.html @wookie919 我只是想知道将所有边转换为无向的运行时复杂性。进行这种转换的好方法是什么? @gyoho 如果BA 的邻居,则添加A 作为B 的邻居。这将花费O(|E|) 时间。 @wookie919 为了进一步优化,我将neighbors的数据结构从List更改为Set以实现O(1)查找neighbors以避免添加重复.

以上是关于使用快速查找算法 (Java) 在有向图中查找所有弱连通分量的优化的主要内容,如果未能解决你的问题,请参考以下文章

在 HTML 页面中快速查找单词的算法

欧拉路径的判断与查找

查找有向图的每个弱连通分量的算法

Xcode 如何快速查找字符串

Java八股文面试题 基础篇 -- 二分查找算法冒泡排序选择排序插入排序希尔排序快速排序

Java八股文面试题 基础篇 -- 二分查找算法冒泡排序选择排序插入排序希尔排序快速排序