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

本文详细介绍Dijkstra算法原理及其实现过程,适用于求解带权图中单源最短路径问题,要求图中不存在负权边。文章通过具体代码展示算法如何找到源点到其他各点的最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值