java中使用es的dsl_基于DSL的基于图论的Java程序中输入图数据的方法

本文介绍了如何使用Domain Specific Language (DSL)在Java程序中更直观地定义图数据,以用于图论算法,如找到最小生成树。作者通过DSL避免了邻接矩阵或邻接列表的复杂输入,展示了DSL的有效语法,并提供了实现该方法的库。
摘要由CSDN通过智能技术生成

java中使用es的dsl

我们大多数人已经编写了一些处理图论算法的程序,例如找到两个顶点之间的最短路径,找到给定图的最小生成树等等。 在这些算法的每一种中,表示图形的编程方式是使用邻接矩阵邻接列表 。 两者都不是定义图形输入的非常直观的方法。 例如,如果未在正确的列和行中进行输入,则邻接矩阵可能会导致错误。 此外,在运行时,您不太确定哪个行/列代表哪个边,当涉及到具有大量顶点的图形的输入时,事情会变得更加复杂。

在我的工程研究期间,我已经用Java实现了许多图形算法,并且在所有这些图形算法中,我都嵌套了for循环以获取邻接矩阵输入。 最近,当我阅读Martin Fowlers的DSL书籍时,我想到了创建DSL来提供图形输入的想法,即DSL,它将允许用户指定顶点,边及其权重。 我选择了已实现的图形算法,只是去除了邻接矩阵输入,而是使用了我创建的DSL。 该算法就像一个魅力。

在这篇文章中,我将通过采用不同的图形输入并为它们显示DSL来显示DSL的有效语法。 然后,我将向您展示我创建的库,该库由图的语义模型,DSL的解析器和词法分析器以及一个简单的构建器API组成,该API从DSL脚本中填充语义模型。 解析器和词法分析器是使用ANTLR生成的,因此该库要求ANTLR Jar在类路径中可用。 最后,我将展示如何使用Kruskals算法将该DSL用于查找最小生成树。

DSL语法和一些示例

下图(g1)的DSL:

图表G1

图表G1

Graph {
  A1 -> B2 (12.3)
  B2 -> C3(0.98)
  C3->D4 (2)
  D4 ->E5 (12.45)
}

请注意,上述DSL中的元素之间存在不同的空间。 这只是为了显示可以编写DSL的不同方式。

下图(g2)的DSL为:

图G2

图G2

Graph{
  A1 -> B2 (12.3)
  B2 -> C3 (0.98)
  C3 -> D4 (2)
  E5
}

请注意,“图形”和“ {”之间没有空格。 这只是为了显示它的不同编写方式。

下图(g3)的DSL为:

图G3

图G3

Graph {
  A -> B (12.3)
  B -> C (0.98)
  C -> D (2)
  D -> E (12.45)
}

现在显示一些无效的DSL脚本:

Graph {
  1A -> B (12.3)
  B -> C (0.98)
}

上面的无效,因为顶点名称以数字开头。

Graph {
}

上面的方法无效,因为Graph希望至少定义一个顶点。 但是它可以具有零个或多个边。

基于DSL的图形输入库

我已经利用ANTLR来完成为我为DSL定义的语法创建词法分析器和解析器的所有任务。 这样,我不必担心创建解析器或担心从DSL输入脚本创建令牌。

解析器和词法分析器类以及语义模型类一起打包到一个jar中,并且必须将这个jar与ANTLR jar一起包括在内,以利用编写用于图形输入的DSL来使用。

DSL jar的结构可以在下面的屏幕截图中看到:

GraphDSL Jar

GraphDSL Jar

图形包中的类与语义模型相对应,即,它们是通用类,可以在不考虑是否有人在使用DSL的情况下使用。 graph.dsl中的类对应于ANTLR为lexer和parser生成的Java类。

ANTLR用于词法分析和解析的语法为:

grammar Graph;

graph: GRAPH_START (edge|vertex)+ GRAPH_END;
edge: (vertex) TO (vertex) weight;
vertex: ID;
weight: '(' NUM ')';
GRAPH_START : 'Graph'([ ])*'{';
GRAPH_END : '}';
WEIGHT_START: '(';
WEIGHT_END: ')'; 
TO: '->';
ID: ^[a-zA-Z][a-zA-Z0-9]*;
NUM: [0-9]*[.]?[0-9]+;
WS: [ \t\r\n]+ -> skip;

上面的语法有待改进,但作为我的第一次尝试,我试图将其保持在这个水平。

  • 此处下载DSL jar(GraphDSL.jar)。
  • 此处下载ANTLR jar(antlr-4.1-complete.jar)。

注意:此DSL是使用ANTLR版本4开发的。

对于使用ANTLR的外部DSL的推荐书是《 语言实现模式:创建自己的域》特定和通用编程语言

Kruskals算法找到最小生成树

用于测试此算法实现的图形为:

样本图

样本图

和DSL相同的是:

Graph  {
  A -> B (7)
  B -> C (8)
  A -> D (5)
  B -> D (9)
  D -> E (15)
  D -> F (6)
  E -> F (8)
  E -> C (5)
  B -> E (7)
  E -> G (9)
  F -> G (11)
}

让我们看一下实现:

package kruskalsalgo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
import graph.Edge;
import graph.Graph;
import graph.Vertex;
import graph.GraphBuilder;
import java.io.IOException;
import java.util.Comparator;

public class KruskalsAlgorithm {

  public static void main(String[] args) throws IOException {

    //Load the graph data from the DSL
    Graph g = new GraphBuilder().buildGraph("graph.gr");
    ArrayList<Set> forest = new ArrayList<Set>();
    ArrayList<Edge> finalEdgeSet = new ArrayList<Edge>();

    //Creating disjoint set of vertices which represents the initial forest
    for (Vertex v : g.getVertices()) {
      Set newSet = new Set();
      newSet.getVertexList().add(v);
      forest.add(newSet); //Creating Disjoint Sets

    }

    //sort the edges in the graph based on their weight
    Collections.sort(g.getEdges(), new Comparator<Edge>(){

      public int compare(Edge o1, Edge o2) {
        return o1.getWeight().compareTo(o2.getWeight());
      }

    });

    for (Edge edge : g.getEdges()) {
      //Find in which set the vertices in the edges belong
      int rep1 = Set.findRep(edge.getFromVertex(), forest);
      int rep2 = Set.findRep(edge.getToVertex(), forest);

      //If in different sets then merge them into one set and pick the edge.
      if (rep1 != rep2) {
        finalEdgeSet.add(edge);
        Set.Union(rep1, rep2, forest);
      }
    }

    System.out.println("The Minimum Spanning tree is");
    for (Edge edge : finalEdgeSet) {
      System.out.println("Vertex: " + edge.getFromVertex().getLabel() + 
              " to Vertex: " + edge.getToVertex().getLabel());
    }

    System.out.println("");

  }//End of Main
}

class Set {

  private ArrayList<Vertex> vertexList;
  private int representative;
  static int count;

  public Set() {
    vertexList = new ArrayList<Vertex>();
    this.representative = ++(Set.count);
  }

  //Find the set identifier in which the given vertex belongs to.
  public static int findRep(Vertex vertex, ArrayList<Set> forest) {
    int rep = 0;
    for (Set set : forest) {
      for (Vertex v : set.getVertexList()) {
        if (v.getLabel().equals(vertex.getLabel())) {
          return set.getRepresentative();
        }
      }
    }

    return rep;
  }

  //Find the set given the step identifier.
  public static Set findSet(int rep, ArrayList<Set> forest) {
    Set resultSet = null;
    for (Set set : forest) {
      if (set.getRepresentative() == rep) {
        return set;
      }
    }
    return resultSet;
  }

  //Merge the set into another and remove it from the main set.
  public static void Union(int rep1, int rep2, ArrayList<Set> forest) {
    Set set1 = Set.findSet(rep1, forest);
    Set set2 = Set.findSet(rep2, forest);

    for (Vertex v : set2.getVertexList()) {
      set1.getVertexList().add(v);
    }
    forest.remove(set2);
  }

  public ArrayList<Vertex> getVertexList() {
    return vertexList;
  }

  public int getRepresentative() {
    return representative;
  }
}

上面的代码从dslgraph.gr加载图形数据。 DSL脚本必须放置在资源包中,以便DSL库可以找到它。

上面代码的输出:

The Minimum Spanning tree is
Vertex: A to Vertex: D
Vertex: E to Vertex: C
Vertex: D to Vertex: F
Vertex: A to Vertex: B
Vertex: B to Vertex: E
Vertex: E to Vertex: G

并以图解方式显示相同的内容

最小生成树

最小生成树


翻译自: https://www.javacodegeeks.com/2013/07/dsl-based-approach-to-input-graph-data-in-graph-theory-based-java-programs.html

java中使用es的dsl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值