Spark GraphX 学习笔记——Dijstra最短路径算法

15 篇文章 0 订阅
6 篇文章 0 订阅
1. Scala中的Dijstra最短路径算法

import org.apache.spark.graphx._
def dijkstra[VD](g:Graph[VD,Double], origin:VertexId): Graph[(VD,Double), Double] = {
	
	/**
	 * 1. 初始化
	 * 遍历图的所有节点
	 * 变为(false, Double.MaxValue的形式,后者是初始化的距离)
	 * 如果是origin节点,则变为0
	 */
	var g2 = g.mapVertices(
		(vid,vd) => (false, if (vid == origin) 0 else Double.MaxValue))
	

	/**
	 * 2. 遍历所有的点,找到最短路径的点,并作为当前顶点
	 */
	for (i <- 1L to g.vertices.count-1) {
	val currentVertexId =
		g2.vertices.filter(!_._2._1)
			.fold((0L,(false,Double.MaxValue)))((a,b) =>
				if (a._2._2 < b._2._2) a else b)
			._1

	// 3. 向与当前顶点相邻的顶点发消息,再聚合消息:取小值作为最短路径
	val newDistances: VertexRDD[Double] = g2.aggregateMessages[Double](

		// sendMsg: 向邻边发送消息,内容为边的距离与最短路径值之和
		ctx => if (ctx.srcId == currentVertexId)
			ctx.sendToDst(ctx.srcAttr._2 + ctx.attr),
		// mergeMsg: 选择较小的值为当前顶点的相邻顶点的最短路径值
		(a,b) => math.min(a,b))

	// 4. 生成结果图
	g2 = g2.outerJoinVertices(newDistances)((vid, vd, newSum) =>
		(vd._1 || vid == currentVertexId,
		math.min(vd._2, newSum.getOrElse(Double.MaxValue))))
	}
	g.outerJoinVertices(g2.vertices)((vid, vd, dist) =>
		(vd, dist.getOrElse((false,Double.MaxValue))._2))
}


2. 执行最短路径距离算法

val myVertices = sc.makeRDD(Array((1L, "A"), (2L, "B"), (3L, "C"),(4L, "D"), (5L, "E"), (6L, "F"), (7L, "G")))

val myEdges = sc.makeRDD(Array(Edge(1L, 2L, 7.0), Edge(1L, 4L, 5.0),Edge(2L, 3L, 8.0), Edge(2L, 4L, 9.0), Edge(2L, 5L, 7.0),Edge(3L, 5L, 5.0), Edge(4L, 5L, 15.0), Edge(4L, 6L, 6.0),Edge(5L, 6L, 8.0), Edge(5L, 7L, 9.0), Edge(6L, 7L, 11.0)))

val myGraph = Graph(myVertices, myEdges)
dijkstra(myGraph, 1L).vertices.map(_._2).collect

输出结果:
res0: Array[(String, Double)] = Array((D,5.0), (A,0.0), (F,11.0), (C,15.0), (G,22.0), (E,14.0), (B,7.0))


3. 包含路径记录的Dijkstra最短路径算法
	在1的基础上用一个List记录寻找的路径

import org.apache.spark.graphx._
def dijkstra[VD](g:Graph[VD,Double], origin:VertexId) = {
	var g2 = g.mapVertices(
		(vid,vd) => (false, if (vid == origin) 0 else Double.MaxValue,List[VertexId]()))

	for (i <- 1L to g.vertices.count-1) {
		val currentVertexId =
			g2.vertices.filter(!_._2._1)
				.fold((0L,(false,Double.MaxValue,List[VertexId]())))((a,b) =>
				if (a._2._2 < b._2._2) a else b)._1

		val newDistances = g2.aggregateMessages[(Double,List[VertexId])](
			ctx => if (ctx.srcId == currentVertexId)
				ctx.sendToDst((ctx.srcAttr._2 + ctx.attr,ctx.srcAttr._3 :+ ctx.srcId)),
			(a,b) => if (a._1 < b._1) a else b)
		g2 = g2.outerJoinVertices(newDistances)((vid, vd, newSum) => {
			val newSumVal = newSum.getOrElse((Double.MaxValue,List[VertexId]()))
			(vd._1 || vid == currentVertexId,
			math.min(vd._2, newSumVal._1),
			if (vd._2 < newSumVal._1) vd._3 else newSumVal._2)})
	}
	g.outerJoinVertices(g2.vertices)((vid, vd, dist) =>
		(vd, dist.getOrElse((false,Double.MaxValue,List[VertexId]())).productIterator.toList.tail))
}

4. 执行包含路径记录的Dijkstra最短路径算法

dijkstra(myGraph, 1L).vertices.map(_._2).collect

	输出结果:
	res1: Array[(String, List[Any])] = Array((D,List(5.0, List(1))), (A,List(0.0, List())), (F,List(11.0, List(1, 4))), (C,List(15.0, List(1, 2))), (G,List(22.0, List(1, 4, 6))), (E,List(14.0, List(1, 2))), (B,List(7.0, List(1))))

	结果解析:(G,List(22.0, List(1, 4, 6)))  1L到G的距离,分别经过1,4,6三个点,总距离为22.0

参考书籍:Spark GraphX 实战

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Dijkstra最路径算法是一种带权图或树的单源最路径算法,它的主要思想是在访问过的顶点中,找到距离源点最近的顶点,然后以该顶点为中介点,更新其他顶点的最路径。 Java实现Dijkstra最路径算法的一种方法是: 1. 创建一个最路径数组dist[],用来存储每个顶点到源点的最距离。 2. 创建一个visited[]数组,用来存储每个顶点是否已经访问过。 3. 初始化源点的最路径为0,其他顶点的最路径为无穷大。 4. 在未访问的顶点中找到最路径的顶点u。 5. 标记顶点u为已访问过。 6. 更新从顶点u出发到其他顶点v的最路径。 7. 重复步骤4-6,直到所有顶点都被访问过。 8. 输出最路径数组dist[]。 这是一个简单的实现方法,也可以使用优先队列优化算法复杂度。 ### 回答2: Dijkstra最路径算法是一种常见的求解图中最路径算法,它可以用来解决许多现实生活中的问题,比如求地图中两点之间的最路程或者求邮递员最优路径等。 Java中实现Dijkstra算法需要以下步骤: 1. 定义图节点类 定义一个GraphNode类,其中包含节点编号、距离和一个HashMap存储与当前节点相邻的其他节点。 2. 编写Dijkstra算法 利用PriorityQueue和HashSet数据结构,实现Dijkstra算法,并返回从起始节点到各个终止节点的最路径。具体实现过程如下: a. 将起始节点的距离设为0,其他节点的距离设为无穷大。 b. 将所有节点添加到PriorityQueue中,按照距离升序排序。 c. 不断从PriorityQueue中取出距离最小的节点,将其加入到HashSet中,更新所有与该节点相邻的节点的距离。 d. 重复上述步骤,直到PriorityQueue为空。 3. 测试 定义一个测试类,通过输入图的节点、边和权重信息,构建出图并测试Dijkstra算法的正确性。 在实现Dijkstra算法时,需要注意以下几点: 1. 若图中存在负权边,则Dijkstra算法不能正确求解最路径,可以采用Bellman-Ford算法解决。 2. 由于Java中PriorityQueue根据元素自然顺序进行排序,因此需要重写GraphNode类的比较方法,使其按照节点距离进行排序。 3. 一般情况下,使用HashMap存储GraphNode类与其他节点的连接关系可以较快地查找到与当前节点相邻的其他节点。 总之,Dijkstra最路径算法是一种优秀的图算法,Java中实现也非常简单,只需要通过PriorityQueue和HashSet等数据结构实现核心算法即可。在实际应用中,我们可以根据不同场景选择不同的算法算法改进来满足实际需求。 ### 回答3: Dijkstra最路径算法是一种经典的图论算法,用于在一个带权有向图中,从一个源点出发,计算出到其他所有点的最路径。该算法采用贪心策略,每次选择当前未确定最路径的节点中,距离源点最近的节点作为下一个确定的节点,直到所有节点都被确定为止。 在Java中,可以使用邻接矩阵或邻接表存储图的结构。在使用邻接矩阵存储图时,可以采用二维数组存储图中每个节点之间的距离。在使用邻接表存储图时,可以采用一个哈希表存储每个节点及其相邻的节点和边的信息。具体实现时,可以定义一个节点类和一个边类,每个节点类包含节点编号、到源点的距离和一个布尔值表示是否已经确定最路径,每个边类包含起点、终点和权值。 Dijkstra算法可以用一个优先队列来存储未确定最路径的节点,每次取出距离源点最近的节点进行更新,同时将与其相邻的节点加入队列中。具体实现时,可以定义一个dist数组存储每个节点到源点的距离,一个parent数组存储每个节点在最路径中的前驱节点,一个优先队列来存储未确定最路径的节点,以及一个visited数组表示每个节点是否已经被访问过。 具体算法步骤如下: 1. 初始化dist数组和visited数组,将源点的距离设为0,将源点加入优先队列中 2. 从优先队列中取出距离源点最近的节点,将其标记为已访问 3. 遍历该节点相邻的所有未访问过的节点,如果通过该节点可以更新距离,则更新dist数组和parent数组,并将节点加入优先队列中 4. 重复步骤2和3,直到所有节点都被访问过 最后,可以通过遍历parent数组来获取从源点到其他节点的最路径。总的时间复杂度为O(ElogV),其中E为边数,V为节点数,由于使用了优先队列,因此算法的时间复杂度与边数相关,适合稠密图和稀疏图的计算。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值