1、三角枚举,从所有无向边对中找到相互连接的三角形

/**
* @Author: xu.dm
* @Date: 2019/7/4 21:31
* @Description: 三角枚举算法
* 三角枚举是在图(数据结构)中找到紧密连接的部分的预处理步骤。三角形由三条边连接,三条边相互连接。
*
* 该算法的工作原理如下:它将所有共享一个共同顶点的边(edge)分组,并构建三元组,即由两条边连接的顶点三元组。
* 最后,通过join操作连接原数据和三元组,过滤所有三元组,去除不存在第三条边(闭合三角形)的三元组。
*
* 输入文件是纯文本文件,必须格式如下:
*
* 边缘表示为顶点ID的对,由空格字符分隔。边线由换行符分隔。
* 例如,"1 2\n2 12\n1 12\n42 63"给出包括三角形的四个(无向)边(1) - (2),(2) - (12),(1) - (12)和(42) - (63)
* (1)
* / \
* (2)-(12)
* 用法:EnumTriangleBasic --edges <path> --output <path>
* 如果未提供参数,则使用{@link EnumTrianglesData}中的默认数据运行程序。
*
*/
public class EnumTriangles {
public static void main(String args[]) throws Exception{
// Checking input parameters
final ParameterTool params = ParameterTool.fromArgs(args); // set up execution environment
final ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment(); // make parameters available in the web interface
env.getConfig().setGlobalJobParameters(params); // read input data
DataSet<EnumTrianglesDataTypes.Edge> edges;
if (params.has("edges")) {
edges = env.readCsvFile(params.get("edges"))
.fieldDelimiter(" ")
.includeFields(true, true)
.types(Integer.class, Integer.class)
.map(new TupleEdgeConverter());
} else {
System.out.println("Executing EnumTriangles example with default edges data set.");
System.out.println("Use --edges to specify file input.");
edges = EnumTrianglesData.getDefaultEdgeDataSet(env);
} // project edges by vertex id
// 对Edge里V1,V2排序,让小的在前
DataSet<EnumTrianglesDataTypes.Edge> edgesById = edges
.map(new EdgeByIdProjector()); DataSet<EnumTrianglesDataTypes.Triad> triangles = edgesById
// build triads
.groupBy(EnumTrianglesDataTypes.Edge.V1)
.sortGroup(EnumTrianglesDataTypes.Edge.V2, Order.ASCENDING)
.reduceGroup(new TriadBuilder())
//通过Triad的第二和第三字段与Edge的第一和第二字段join,找出有第二和第三有路径的对子。
.join(edgesById)
.where(EnumTrianglesDataTypes.Triad.V2, EnumTrianglesDataTypes.Triad.V3)
.equalTo(EnumTrianglesDataTypes.Edge.V1, EnumTrianglesDataTypes.Edge.V2)
// filter triads
.with(new TriadFilter()); // emit result
if (params.has("output")) {
triangles.writeAsCsv(params.get("output"), "\n", ",");
// execute program
env.execute("Basic Triangle Enumeration Example");
} else {
System.out.println("Printing result to stdout. Use --output to specify output path.");
triangles.print();
}
} //转换Tuple2类型到Edge类型
@FunctionAnnotation.ForwardedFields("0;1")
public static class TupleEdgeConverter implements MapFunction<Tuple2<Integer,Integer>, EnumTrianglesDataTypes.Edge>{
private final EnumTrianglesDataTypes.Edge outEdge = new EnumTrianglesDataTypes.Edge();
@Override
public EnumTrianglesDataTypes.Edge map(Tuple2<Integer, Integer> value) throws Exception {
outEdge.copyVerticesFromTuple2(value);
return outEdge;
}
} /**
* Projects an edge (pair of vertices) such that the id of the first is smaller than the id of the second.
* 转换一对边,如果first大于second,则互相交换
* */
private static class EdgeByIdProjector implements MapFunction<EnumTrianglesDataTypes.Edge, EnumTrianglesDataTypes.Edge>{
@Override
public EnumTrianglesDataTypes.Edge map(EnumTrianglesDataTypes.Edge value) throws Exception { //flip vertices 反转顶点
if(value.getFirstVertex()>value.getSecondVertex())
{
value.flipVertices();
}
return value;
}
} /**
* Builds triads (triples of vertices) from pairs of edges that share a vertex.
* The first vertex of a triad is the shared vertex, the second and third vertex are ordered by vertexId.
* Assumes that input edges share the first vertex and are in ascending order of the second vertex.
* 构造triads(三位一体结构),即经过分组排序后,拥有共同顶点的edge,按顺序(分组后顶点需要升序)组合成三体
* 构成Triad的第一个顶点是分组id,也是分组里所有对子(edge)共享的id,第二和第三个顶点是分组的对子(edge)里的第二个顶点,edge他们是按升序排列。
* 分组结构类似如下,s1就是共享的顶点,f1到f3是按升序排列的对子(s1-f1),(s1-f2),(f1-f3)。
* f1
* /
* s1 一 f2
* \
* f3
*/
@FunctionAnnotation.ForwardedFields("0")
private static class TriadBuilder
implements GroupReduceFunction<EnumTrianglesDataTypes.Edge, EnumTrianglesDataTypes.Triad>{
private final List<Integer> vertices = new ArrayList<>();
private final EnumTrianglesDataTypes.Triad outTriad = new EnumTrianglesDataTypes.Triad(); @Override
public void reduce(Iterable<EnumTrianglesDataTypes.Edge> values, Collector<EnumTrianglesDataTypes.Triad> out) throws Exception {
final Iterator<EnumTrianglesDataTypes.Edge> edges = values.iterator(); // clear vertex list
vertices.clear(); // read first edge
EnumTrianglesDataTypes.Edge firstEdge = edges.next();
outTriad.setFirstVertex(firstEdge.getFirstVertex()); vertices.add(firstEdge.getSecondVertex()); // build and emit triads
if(edges.hasNext()){
Integer higherVertexId = edges.next().getSecondVertex(); //combine vertex with all previously read vertices
for(Integer lowVertexId:vertices){
outTriad.setSecondVertex(lowVertexId);
outTriad.setThirdVertex(higherVertexId);
out.collect(outTriad);
}
vertices.add(higherVertexId);
}
}
} /**
* Filters triads (three vertices connected by two edges) without a closing third edge.
* 过滤没有闭合边的三体
* */
private static class TriadFilter
implements JoinFunction<EnumTrianglesDataTypes.Triad, EnumTrianglesDataTypes.Edge, EnumTrianglesDataTypes.Triad>{
@Override
public EnumTrianglesDataTypes.Triad join(EnumTrianglesDataTypes.Triad first, EnumTrianglesDataTypes.Edge second) throws Exception {
return first;
}
} }

2、三角枚举所需要数据结构等

public class EnumTrianglesDataTypes {
/**
* A POJO storing two vertex IDs.
*/
public static class Edge extends Tuple2<Integer, Integer> {
private static final long serialVersionUID = 1L; public static final int V1 = 0;
public static final int V2 = 1; public Edge() {} public Edge(final Integer v1, final Integer v2) {
this.setFirstVertex(v1);
this.setSecondVertex(v2);
} public Integer getFirstVertex() {
return this.getField(V1);
} public Integer getSecondVertex() {
return this.getField(V2);
} public void setFirstVertex(final Integer vertex1) {
this.setField(vertex1, V1);
} public void setSecondVertex(final Integer vertex2) {
this.setField(vertex2, V2);
} public void copyVerticesFromTuple2(Tuple2<Integer, Integer> t) {
this.setFirstVertex(t.f0);
this.setSecondVertex(t.f1);
} public void copyVerticesFromEdgeWithDegrees(EdgeWithDegrees ewd) {
this.setFirstVertex(ewd.getFirstVertex());
this.setSecondVertex(ewd.getSecondVertex());
} public void flipVertices() {
Integer tmp = this.getFirstVertex();
this.setFirstVertex(this.getSecondVertex());
this.setSecondVertex(tmp);
}
} /**
* A POJO storing three vertex IDs.
*/
public static class Triad extends Tuple3<Integer, Integer, Integer> {
private static final long serialVersionUID = 1L; public static final int V1 = 0;
public static final int V2 = 1;
public static final int V3 = 2; public Triad() {} public void setFirstVertex(final Integer vertex1) {
this.setField(vertex1, V1);
} public void setSecondVertex(final Integer vertex2) {
this.setField(vertex2, V2);
} public void setThirdVertex(final Integer vertex3) {
this.setField(vertex3, V3);
}
} /**
* A POJO storing two vertex IDs with degree.
*/
public static class EdgeWithDegrees extends Tuple4<Integer, Integer, Integer, Integer> {
private static final long serialVersionUID = 1L; public static final int V1 = 0;
public static final int V2 = 1;
public static final int D1 = 2;
public static final int D2 = 3; public EdgeWithDegrees() { } public Integer getFirstVertex() {
return this.getField(V1);
} public Integer getSecondVertex() {
return this.getField(V2);
} public Integer getFirstDegree() {
return this.getField(D1);
} public Integer getSecondDegree() {
return this.getField(D2);
} public void setFirstVertex(final Integer vertex1) {
this.setField(vertex1, V1);
} public void setSecondVertex(final Integer vertex2) {
this.setField(vertex2, V2);
} public void setFirstDegree(final Integer degree1) {
this.setField(degree1, D1);
} public void setSecondDegree(final Integer degree2) {
this.setField(degree2, D2);
} public void copyFrom(final EdgeWithDegrees edge) {
this.setFirstVertex(edge.getFirstVertex());
this.setSecondVertex(edge.getSecondVertex());
this.setFirstDegree(edge.getFirstDegree());
this.setSecondDegree(edge.getSecondDegree());
}
}
}

3、测试数据

public class EnumTrianglesData {
public static final Object[][] EDGES = {
{1, 2},
{1, 3},
{1, 4},
{1, 5},
{2, 3},
{2, 5},
{3, 4},
{3, 5},
{3, 7},
{3, 8},
{5, 6},
{7, 8}
}; public static DataSet<EnumTrianglesDataTypes.Edge> getDefaultEdgeDataSet(ExecutionEnvironment env) { List<EnumTrianglesDataTypes.Edge> edges = new ArrayList<EnumTrianglesDataTypes.Edge>();
for (Object[] e : EDGES) {
edges.add(new EnumTrianglesDataTypes.Edge((Integer) e[0], (Integer) e[1]));
} return env.fromCollection(edges);
}
}
 

flink 实现三角枚举EnumTriangles算法详解的更多相关文章

  1. [转] KMP算法详解

    转载自:http://www.matrix67.com/blog/archives/115 KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段.    我们这里说的K ...

  2. KMP算法详解(转自中学生OI写的。。ORZ!)

    KMP算法详解 如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段. 我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法.KMP算法是拿来处理字符串匹配的.换句 ...

  3. BSGS(Baby Steps,Giant Steps)算法详解

    BSGS(Baby Steps,Giant Steps)算法详解 简介: 此算法用于求解 Ax≡B(mod C): 由费马小定理可知: x可以在O(C)的时间内求解:  在x=c之后又会循环: 而BS ...

  4. KMP算法详解&&P3375 【模板】KMP字符串匹配题解

    KMP算法详解: KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt(雾)提出的. 对于字符串匹配问题(such as 问你在abababb中有多少个 ...

  5. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

  6. kmp算法详解

    转自:http://blog.csdn.net/ddupd/article/details/19899263 KMP算法详解 KMP算法简介: KMP算法是一种高效的字符串匹配算法,关于字符串匹配最简 ...

  7. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

  8. 【转】AC算法详解

    原文转自:http://blog.csdn.net/joylnwang/article/details/6793192 AC算法是Alfred V.Aho(<编译原理>(龙书)的作者),和 ...

  9. EM算法详解

    EM算法详解 1 极大似然估计 假设有如图1的X所示的抽取的n个学生某门课程的成绩,又知学生的成绩符合高斯分布f(x|μ,σ2),求学生的成绩最符合哪种高斯分布,即μ和σ2最优值是什么? 图1 学生成 ...

随机推荐

  1. Falling back to java on path. This behavior is deprecated

    windows启动elasticsearch报错:warning: Falling back to java on path. This behavior is deprecated. Specify ...

  2. 6.Python网络编程_全局变量基础

    变量作用域: 一般在函数体外定义的变量成为全局变量,在函数内部定义的变量称为局部变量.全局变量所有作用域都可用,局部变量只能在本函数可用,变量的使用顺序是,局部变量 > 全局变量, 也就是说:优 ...

  3. Xshell使用教程

    Xshell 是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议.Xshell 通过互联网到远程主机的安全连接以及它创新性的设 ...

  4. 浅谈C++ STL vector 容器

    浅谈C++ STL vector 容器 本篇随笔简单介绍一下\(C++STL\)中\(vector\)容器的使用方法和常见的使用技巧.\(vector\)容器是\(C++STL\)的一种比较基本的容器 ...

  5. LG5536 「XR-3」核心城市 树的直径

    问题描述 LG5536 题解 两次 \(\mathrm{dfs}\) 求树的直径. 然后找到树的直径的中点. 然后按照 子树中最深的点深度-自己深度 排序,贪心选取前 \(k\) 个. \(\math ...

  6. luoguP2597 [ZJOI2012]灾难

    题意 这题思路好奇怪啊 见到有向无环图显然是要拓朴排序,不妨按照被吃向吃连边,那么\(x\)灭绝当且仅当x的入点都灭绝,于是考虑怎样x的入点都灭绝 比如4号节点,它灭绝当且仅当2和3灭绝,2和3灭绝当 ...

  7. NOIP模拟赛 最佳组合

    题目描述 Description \(Bzeroth\) 大陆最终还是覆灭了,所以你需要为地灾军团服务了. 地灾军团军师黑袍不擅长写题面,所以你只需要看简化版的题意即可. 给定 \(3\) 个长度均为 ...

  8. 开源项目 13 log4net

    原文:https://www.cnblogs.com/pudefu/p/9300697.html 官方的api: http://logging.apache.org/log4net/release/s ...

  9. ES2019 的新特性

    JavaScript 不断演变,每次迭代都会得到一些新的内部更新.让我们来看看 ES2019 有哪些新的特性,并加入到我们日常开发中 Array.prototype.flat() Array.prot ...

  10. JDK的小Bug你了解么?

    ​用了这么长时间的JDK了,有没有老铁发现JDK的bug呢?从最早版本的JDK1.2到现在普及开的JDK1.8以来,JAVA经历了这么多年的风风雨雨,依然坚持在一线上,是不是感觉很神奇,但是,有没有多 ...