面试官问我:"如何实现你项目中的这块代码."我说:"看好了."

147 阅读2分钟

首先假设传进来一个json结构比如

   {node1:node2;
    node2:node3;
    node2:node4;
    node3:node5;
    node4;node5;}       

那现在要实现三个功能第一你要解析这个json结构,第二你要解析后来找到json结构的一个头节点,第三你需要找到任意一个节点的后继节点.
那我们现在来思考第一个功能解析,我期望的一个结构是

{
    node1=[node2],
    node2=[node3, node4],
    node3=[node5],
    node4=[node5],
    node5=[nodeend],
    nodeend=[]
}

他本质上其实是一个邻接表Map<String, List<String>>他非常适合

  • 图遍历
  • 找路径
  • 拓扑排序
  • 检测环
  • 找入度/出度

来我们把具体代码实现一下

public static Map<String, List<String>> parseGraph(String input) {
    Map<String, List<String>> graph = new HashMap<>();

    // 去掉首尾的 {}
    String content = input.substring(1, input.length() - 1);

    // 按 ; 切分每条边
    String[] relations = content.split(";");
    //form和to节点

    for (String relation : relations) {
        String[] pair = relation.split(":");
        String from = pair[0];
        String to = pair[1];

        // 如果 from 还没在 map 里,先放一个空列表
        if (!graph.containsKey(from)) {
            graph.put(from, new ArrayList<>());
        }
        graph.get(from).add(to);

        // 保证 to 节点也在 map 里
        if (!graph.containsKey(to)) {
            graph.put(to, new ArrayList<>());
        }
    }

    return graph;
}

上面我们对json结构进行了一个解析接下来呢我们来找到他的头节点

头节点是什么

在这张图里,头节点可以理解为:

没有任何前驱节点的节点,也就是入度为 0 的节点。

比如这里:

  • node2 被 node1 指向
  • node3 被 node2 指向
  • node4 被 node2 指向
  • node5 被 node3 和 node4 指向
  • nodeend 被 node5 指向

只有 node1 没有被任何节点指向,所以它就是头节点。 接下来我们写一下代码

//找头节点

public static List<String> findHeadNodes(Map<String, List<String>> graph) {
    List<String> result = new ArrayList<>();

    // 记录所有出现过的节点
    Set<String> allNodes = new HashSet<>();

    // 记录“被别人指向过”的节点
    Set<String> pointedNodes = new HashSet<>();

    // 遍历图
    for (String from : graph.keySet()) {
        // 当前 key 本身也是一个节点
        allNodes.add(from);

        // 当前节点的所有后继节点
        List<String> nextNodes = graph.get(from);

        for (String to : nextNodes) {
            // 后继节点也属于图中的节点
            allNodes.add(to);

            // to 被 from 指向过,说明它不是头节点
            pointedNodes.add(to);
        }
    }

    // 如果一个节点从来没有被指向过,那它就是头节点
    for (String node : allNodes) {
        if (!pointedNodes.contains(node)) {
            result.add(node);
        }
    }

    return result;
}

那最后一个问题的就非常简单了找到一个节点的后继节点

public static List<String> findSuccessors(Map<String, List<String>> graph, String node) {
if (graph == null || node == null) {
return Collections.emptyList();
}
return graph.getOrDefault(node, Collections.emptyList());

}

就这样我们完美的解决了面试官的问题以及类似的问题都可以这样解决