Spark GraphX实现Bron–Kerbosch算法-极大团问题

6 篇文章 0 订阅
5 篇文章 0 订阅

首先,说明两个概念:团、极大团。

  • clique)是一个无向图(undirected graph )的子图,该子图中任意两个顶点之间均存在一条边。又叫做完全子图。
  • 极大团(maximal clique)是一个团,该团不能被更大的团所包含,换句话说,再也不存在一个点与该团中的任意顶点之间存在一条边。

研究极大团的问题对社区发现等场景有较高的理论价值和现实意义。求一个无向图中的极大团问题是一个经典的NP完全问题,1973年曾提出了一个Bron-Kerbosch算法用来解决该问题,其伪代码如下:

 BronKerbosch(R, P, X):
       if P and X are both empty:
           report R as a maximal clique
       for each vertex v in P:
           BronKerbosch(R ⋃ {v}, P ⋂ N(v), X ⋂ N(v))
           P := P \ {v}
           X := X ⋃ {v}

该算法中有四个集合:R,P,X,N(v),其中:

R:目前已经在团中的顶点的集合

P:可能在团中的顶点的集合

X:不被考虑的顶点的集合

N(v):顶点v的所有直接邻居


以一个6个顶点的图为例:


用Spark GraphX实现Bron Kerbosch算法,搜索该图的极大团,代码如下:

import org.apache.spark.graphx.{Edge, EdgeDirection, Graph, VertexId}
import org.apache.spark.{SparkConf, SparkContext}

import scala.collection.mutable
import scala.collection.mutable.Set

object FindMaximalCliques {
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("findMaximalCliques").setMaster("local")
    val sc: SparkContext = new SparkContext(conf)
    //定义顶点
    val vertexArray = Array(
      (1L,null),
      (2L,null),
      (3L,null),
      (4L,null),
      (5L,null),
      (6L,null)
    )
    //定义边
    val edgeArray = Array(
      Edge(6L, 4L,null),
      Edge(4L, 3L,null),
      Edge(4L, 5L,null),
      Edge(5L, 2L,null),
      Edge(3L, 2L,null),
      Edge(5L, 1L,null),
      Edge(2L, 1L,null)
    )

    //顶点和边转化为RDD
    val vertexRDD = sc.parallelize(vertexArray)
    val edgeRDD  = sc.parallelize(edgeArray)

    //根据顶点和边创建图
    val graph= Graph(vertexRDD,edgeRDD)

    //创建一个Map集合。key是图中的所有顶点;value是一个Set集合,保存了该key的所有邻居顶点
    val map: Map[VertexId, Set[VertexId]] = graph.collectNeighborIds(EdgeDirection.Either).collect()
      .map(t => {
        var set: mutable.Set[VertexId] = Set[VertexId]()
        t._2.foreach(t=>{set+=t})
        (t._1, set)
      }).toMap

    //R集合,初始值为空
    var R = Set[VertexId]()
    //P集合,初始值为所有的顶点
    var P = Set[VertexId]()
    //将所有的顶点添加到P集合中
    vertexRDD.collect().foreach(t=>{P+=t._1})
    //X集合,初始值为空
    var X = Set[VertexId]()

    //搜索极大团
    bronKerboschl(R,P,X,map)
  }

  /**
    * 搜索极大团的方法
    * @param R 目前已经在团中的顶点的集合
    * @param P 可能在团中的顶点的集合
    * @param X 不被考虑的顶点的集合
    * @param map Map集合,通过顶点获取该顶点的所有邻居顶点集合
    */
  def bronKerboschl(R:Set[VertexId],P:Set[VertexId],X:Set[VertexId],map:Map[VertexId, Set[VertexId]]): Unit ={
    if(P.toList.length ==0 && X.toList.length ==0){
      println("find a maximal cilique:"+R)
    }else {
      for (v <- P) {
        var Nv: Set[VertexId] = map.get(v).get
        bronKerboschl(R+v, P.intersect(Nv), X.intersect(Nv), map)
        X += v
        P -= v
      }
    }
  }

}

结果为:

find a maximal cilique:Set(1, 5, 2)
find a maximal cilique:Set(5, 4)
find a maximal cilique:Set(2, 3)
find a maximal cilique:Set(6, 4)
find a maximal cilique:Set(3, 4)


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值