图论 : 最短路径实现(通用) - Dijkstra 、Bellman-Ford 、Floyd- Java

最短路径和

最短路径是指两点之间权值之和最小的路径之和,广泛应用于路径规划问题,有向图、无向图均适用,但不能有负权环:

在这里插入图片描述
上图C - D - F之间构成了负权环,A 到 F之间的最短路径A -> C -> D -> F -> C -> D -> F…可以无限缩短,即不存在最短路径。

单源最短路径最经典的实现有Dijkstra、Bellman-Ford两种算法。

Dijkstra算法实现

使用前提:单源最短路径,不能有负权边

算法原理:按路径长度递增的次序依次产生最短路径

时间复杂度:O(ElogV)

以下图为例,求A到个点的最短路径:

在这里插入图片描述

举一个贴近生活的例子:将连在一起的一堆石头以某一个为源点向上顺势拧起,直至石头全被提起。Dijkstra算法实现原理和拧石头类似,后离开桌面的石头一定是被先离开桌面的石头提起的,并且当可能被多条绳子提起时,只有最短那根绳子才能将其提起。

算法模拟

Dijkstra算法实现过程;

黑色:源点
红色:当前正在被更新最短路径的点
紫色:求出最短路径的点

首先,A到A的最短路径为0,将A提起,下一步有可能被提起的点是与A直接相连的点,所以对A的所有出度的边进行松弛操作,即更新B D E的最短路径:

在这里插入图片描述

扫描路径和列,路径和最小的即是下一个被提起的点,求出了该点 (B点) 的最短路径。下一个有可能被提起的点必然是与A、C直接相连的点,对B的所有出度进行松弛操作,更新与B直接相连的点C的最短路径:

在这里插入图片描述

同样扫描路径和列(标位紫色的是已经求出最短路径的点,不再扫描),找出这轮最短路径点D点,更新与D相连的点E、C的最短路径:

在这里插入图片描述
同样扫描,找出这轮的最短路径是C点,更新与C直接相连的E点的最短路径:

在这里插入图片描述

再次扫描,只有E点一点,找出E点最短路径,到此求出了所有点的最短路径:

在这里插入图片描述

封装

封装边:


	private static class Edge<V, E>{
   
		E weight;
		Vertex<V, E> from; //源顶点
		Vertex<V, E> to; //目的顶点
		
		Edge(Vertex<V, E> from, Vertex<V, E> to){
   
			this.from = from;
			this.to = to;
		}
		Edge(Vertex<V, E> from, Vertex<V, E> to, E weight){
   
			this(from, to);
			this.weight = weight;
		}
		
		//!!!边集用Set、顶点集Map存储    底层都是hash表+链表+红黑树  必须在Edge、Vertex类里实现各自的HashCode和equals方法
		@Override
		public boolean equals(Object obj) {
   
			Edge<V, E> edge = (Edge<V, E>)obj;
			//如果两条边源顶点和目的顶点都相同则视为同一条边
			return Objects.equals(this.from, edge.from) && Objects.equals(this.to, edge.to);
		}
		@Override
		public int hashCode() {
   
			return from.hashCode() * 31 + to.hashCode();
		}
	}

封装顶点:


	private static class Vertex<V, E>{
   
		V value;
		Set<Edge<V, E>> inEdges = new HashSet<>();
		Set<Edge<V, E>> outEdges = new HashSet<>();
		Vertex(V value){
   
			this.value = value;
		}
		@Override
		public boolean equals(Object obj) {
   
			return Objects.equals(value, ((Vertex<V, E>)obj).value);
		}
		@Override
		public int hashCode() {
   
			return value == null ? 0 : value.hashCode();
		}
	}

封装路径信息:


	public static class PathInfo<V, E>{
   
		private E weight;
		private List<Edge<V, E>> path = new LinkedList<>();  //用链表存储路径
		
		public String getPathInfo() {
   
			StringBuilder s = new StringBuilder();
			for (Edge<V, E> edge : path) {
   
				s = s.append(edge.from.value +"-->" + edge.to.value + "  "
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值