Digraph.java

package com.aiddroid.algo;

import java.util.HashMap;
import java.util.HashSet;

/**
 * 有向图
 */
public class Digraph {

    // 节点数
    private int V = 0;

    // 边数
    private int E = 0;

    // 邻接表,存放边(节点间的连接关系)
    private HashMap<String, HashSet<String>> adj;

    /**
     * 构造函数
     */
    public Digraph() {
        this.adj = new HashMap<String, HashSet<String>>();
    }

    public int V() {
        return this.V;
    }

    public int E() {
        return this.E;
    }

    /**
     * 添加节点
     * @param from
     * @param to
     */
    public void addEdge(String from, String to) {
        // 如果添加边时节点不存在,则初始化节点
        if (!this.adj.keySet().contains(from)) {
            this.adj.put(from, new HashSet<String>());
            this.V++;
        }
        if (!this.adj.keySet().contains(to)) {
            this.adj.put(to, new HashSet<String>());
            this.V++;
        }
        
        HashSet<String> s = this.adj.get(from);
        s.add(to);
        this.adj.put(from, s);
        this.E++;
    }

    private Iterable<String> adj(String key) {
        return this.adj.get(key);
    }

    /**
     * 获取反转的有向图
     *
     * @return
     */
    public Digraph reverse() {
        Digraph R = new Digraph();
        for (String key : this.adj.keySet()) {
            for (String w : this.adj(key)) {
                R.addEdge(w, key);
            }
        }
        return R;
    }

    /**
     * 转化为doT图
     * @return 
     */
    public String toDoT() {
        String doT = "strict digraph G {\n";
        String nodes = "";
        String links = "";
        for (String key : this.adj.keySet()) {
            nodes += "\t\"%s\" [ label=\"%s\" ];\n".formatted(key, key);
            for (String to: this.adj(key)) {
                links += "\t\"%s\" -> \"%s\";\n".formatted(key, to);
            }
        }
        doT += nodes;
        doT += links;
        doT += "}";
        
        return doT;
    }
}


Application.java

package com.aiddroid.algo;

import java.util.List;

/**
 * 测试代码
 */
public class Application {

    public static void main(String[] args) {
        // 初始化有向图,并添加边      
        Digraph digraph = new Digraph();
        digraph.addEdge("中国", "广东");
        digraph.addEdge("广东", "广州");
        digraph.addEdge("广东", "深圳");
        
        digraph.addEdge("中国", "湖北");
        digraph.addEdge("湖北", "武汉");
        digraph.addEdge("武汉", "广州");
        
        digraph.addEdge("中国", "北京");
        digraph.addEdge("北京", "深圳");
        
        System.out.println(digraph.toDoT());
    }

}

输出结果(doT图):

strict digraph G {
	"广州" [ label="广州" ];
	"广东" [ label="广东" ];
	"中国" [ label="中国" ];
	"湖北" [ label="湖北" ];
	"武汉" [ label="武汉" ];
	"深圳" [ label="深圳" ];
	"北京" [ label="北京" ];
	"广东" -> "广州";
	"广东" -> "深圳";
	"中国" -> "广东";
	"中国" -> "湖北";
	"中国" -> "北京";
	"湖北" -> "武汉";
	"武汉" -> "广州";
	"北京" -> "深圳";
}

doT渲染结果如下(https://dreampuf.github.io ):


实际上,我们并不需要手工实现有向图,jgrapht库已经提供了很好的支持,在maven项目中直接引用就行(pom.xml)

        <dependency>
            <groupId>org.jgrapht</groupId>
            <artifactId>jgrapht-core</artifactId>
            <version>1.5.0</version>
        </dependency>
        
        <dependency>
            <groupId>org.jgrapht</groupId>
            <artifactId>jgrapht-io</artifactId>
            <version>1.5.0</version>
        </dependency>

jgrapht绘制有向图示例:

import java.io.Writer;
import java.io.StringWriter;

import org.jgrapht.*;
import org.jgrapht.graph.*;
import org.jgrapht.nio.*;
import org.jgrapht.nio.dot.*;

/**
 * 测试代码
 */
public class Application {

    public static void main(String[] args) {
        // 初始化有向图
        Graph<String, DefaultEdge> directedGraph =
            new DefaultDirectedGraph<String, DefaultEdge>(DefaultEdge.class);

        // 构建有向图
        directedGraph.addVertex("中国");
        directedGraph.addEdge("中国", "北京");
        directedGraph.addEdge("中国", "深圳");

        renderDirectedGraph(directedGraph);
    }

    // 绘制doT图
    private void renderDirectedGraph(Graph<String, DefaultEdge> directedGraph) {
        DOTExporter<String, DefaultEdge> exporter = new DOTExporter<>(v -> {
            // 移除特殊字符
            return v.replaceAll("[^a-zA-Z0-9]", "_");
        });

        // 为节点添加标签
        exporter.setVertexAttributeProvider((v) -> {
            Map<String, Attribute> map = new LinkedHashMap<>();
            map.put("label", DefaultAttribute.createAttribute(v.toString()));
            return map;
        });

        Writer writer = new StringWriter();
        exporter.exportGraph(directedGraph, writer);
        
        // 输出doT图
        System.out.println(writer.toString());
    }
}

发表评论

Post Navigation