java编写Dijkstra单源最短路径算法

Dijkstra单源最短路径算法

此算法用于求出图中的一个源点到其余各点的最短路径,此图必须为带权图且不能有负权值,是否为有向图则没关系

算法思想关键:

设定一个源点s,遍历它的邻边,求出邻边中权值最小的那条边e,获得e另一端点v,则s到v的最短路径必定就是e,因为s到其他点的长度本来就长于e,若还从其他点折回v的话,那长度一定长于e(因此不能有负权边)。然后继续遍历v的邻边,若邻边中最短的边h的另一端点a是之前源点s(即v的上一级节点)遍历过的,则判断h的长度加上e的长度是否小于之前获得的s->a的长度,小于则更新a的相关数据,下面看代码:

类Dijkstra:

public class Dijkstra {
	
	private SparseGraph sg;      //有向图
	private int s;     //源点
	private int[] distTo;    //存储源点到各点的距离
	private boolean[] marked;
	private ArrayList<Edge> from=new ArrayList<Edge>();   //存储指向该顶点的边Edge
	
	
	public Dijkstra(SparseGraph sg, int s) {
		this.sg = sg;
		this.s = s;
		distTo=new int[sg.V()];
		marked=new boolean[sg.V()];
		for(int i=0;i<sg.V();i++){
			distTo[i]=0;
			marked[i]=false;
			from.add(null);
		}
		IndexMinHeap imh=new IndexMinHeap(sg.V());
		//Dijkstra
		marked[s]=true;
		imh.insert(s, distTo[s]);
		while(!imh.isEmpty()){
			int v=imh.extractMinIndex();
			//distTo[v]就是s到v的最短距离
			
			marked[v]=true;
			
			ArrayList<Edge> arr=sg.getGraph(v);
			Iterator<Edge> ite=arr.iterator();
			while(ite.hasNext()){
				Edge e=ite.next();
				int w=e.other(v);
				if(!marked[w]){     //w没有marked即表示s到w的最短路径没有找到
					if(from.get(w)==null||distTo[v]+e.wt()<distTo[w]){  //from.get(w)==null表示e这条路径没访问过
						distTo[w]=distTo[v]+e.wt();          //若 distTo[v]+e.wt()<distTo[w],则此操作为松弛操作
						from.set(w, e);                  //若 distTo[v]+e.wt()<distTo[w],则此操作更新了s到w的最短路径的最后一段
						if(imh.contain(w))
							imh.set(w, distTo[w]);
						else
							imh.insert(w, distTo[w]);
					}
				}
			}
		}
	}
	//返回源点到w点的最短路径的权值和
	public int shortestPathTo(int w){
		return distTo[w];
	}
	//源点到w点是否有路径
	public boolean hasPathTo(int w){
		return marked[w];
	}
	
	private void shortestPath(int w,ArrayList<Edge> path){
		Stack<Edge> s = new Stack<Edge>();
		Edge e=from.get(w);      //得到指向w点的路径
		while(e!=null){
			s.push(e);
			e=from.get(e.v());
		}
		while(!s.isEmpty()){
			e=s.peek();
			path.add(e);
			s.pop();
		}
	}
	
	public void showPath(int w){
		assert(w>=0&&w<sg.V());
		ArrayList<Edge> path=new ArrayList<Edge>();
		shortestPath(w,path);
		for(int i=0;i<path.size();i++){
			System.out.print(path.get(i).v()+"->");
			if(i==path.size()-1){
				System.out.print(path.get(i).w());
			}
		}
	}

	public static void main(String[] args) {
		int N=10;  //顶点
		int M=60;   //边
		SparseGraph sg=new SparseGraph(N,true);
		for(int i=0;i<M;i++){
			sg.addEdge(new Random().nextInt(N), new Random().nextInt(N),new Random().nextInt(40)+1);
		}
		Dijkstra di=new Dijkstra(sg,3);
		for(int i=0;i<sg.V();i++){
			if(di.hasPathTo(i)){
				di.showPath(i);
			}		
			System.out.println();
		}
	}

}
结果如图:


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是Dijkstra单源最短路径算法的Python实现: ```python import sys class Graph: def __init__(self, vertices): self.V = vertices self.graph = [[0 for column in range(vertices)] for row in range(vertices)] def printSolution(self, dist): print("Vertex \t Distance from Source") for node in range(self.V): print(node, "\t\t", dist[node]) def minDistance(self, dist, sptSet): min = sys.maxsize for v in range(self.V): if dist[v] < min and sptSet[v] == False: min = dist[v] min_index = v return min_index def dijkstra(self, src): dist = [sys.maxsize] * self.V dist[src] = 0 sptSet = [False] * self.V for cout in range(self.V): u = self.minDistance(dist, sptSet) sptSet[u] = True for v in range(self.V): if self.graph[u][v] > 0 and sptSet[v] == False and dist[v] > dist[u] + self.graph[u][v]: dist[v] = dist[u] + self.graph[u][v] self.printSolution(dist) # 测试 g = Graph(9) g.graph = [[0, 4, 0, 0, 0, 0, 0, 8, 0], [4, 0, 8, 0, 0, 0, 0, 11, 0], [0, 8, 0, 7, 0, 4, 0, 0, 2], [0, 0, 7, 0, 9, 14, 0, 0, 0], [0, 0, 0, 9, 0, 10, 0, 0, 0], [0, 0, 4, 14, 10, 0, 2, 0, 0], [0, 0, 0, 0, 0, 2, 0, 1, 6], [8, 11, 0, 0, 0, 0, 1, 0, 7], [0, 0, 2, 0, 0, 0, 6, 7, 0]] g.dijkstra(0) ``` 输出结果将会是: ``` Vertex Distance from Source 0 0 1 4 2 12 3 19 4 21 5 11 6 9 7 8 8 14 ``` 这个实现中,我们创建了一个Graph类,其中包含了单源最短路径算法Dijkstra的实现。在测试中,我们创建了一个有9个节点的图,并使用Dijkstra算法计算从第0个节点到其他节点的最短路径。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值