Java用Dijkstra计算有权图单源点最短路径

引入

随手笔记,做的不好见谅。
DijKstra算法个人理解

  1. 每次取出最短路径的顶点
  2. 由该点进行扩散,遍历该点的邻接点得到新点
  3. 若源点到该点+该点到新点<源点到新点,就更新源点到新点的值
  4. 添加进该新点进队列下次由它扩散,如此循环

代码

1.用邻接矩阵表示的图

import java.util.Scanner;

public class DijkstraMatrixShoterPath {
	static int n;// 点数
	static int e;// 边数
	static int G[][];// 领接矩阵
	static boolean visit[];// 是否访问过的节点
	static int dis[];// 路径 dis[i] = j, 默认1到节点i最短路径j
	static int path[];// 记录路线
		
	// 寻找源点到节点最下的路径节点,并且没有访问过的
	public static int findMinNode(){
		int max = Integer.MAX_VALUE;
		int node = -1;
		for(int i = 1; i <= n; i++){
			if(dis[i] < max && !visit[i]){
				max = dis[i];
				node = i;
			}
		}
		return node;// 如果返回-1代表没找到
	}
	
	// dij
	public static void dijstrax(int yuan){
		// 初始化源点为0代表最小,第一个取出
		dis[yuan] = 0;
		path[yuan] = -1;// 源点记录区分
		int u = 0;
		while(true){
			u = findMinNode();
			// =-1代表都访问过并扩散了,可以退出了
			if(u == -1){
				break;
			}
			// 标记访问了当前节点
			visit[u] = true;
			// 以当前u节点,扩散它的领接点
			for(int j = 1; j <= n; j++){
				/*
				当前j点没访问过,并且有路径。
				*/
				if(!visit[j] && G[u][j] < Integer.MAX_VALUE){
					// 如果:源点到点u+u点到j点 < 源点到j点,就更新源点到j点的距离。
					if(dis[u] + G[u][j] < dis[j]){
						dis[j] = dis[u] + G[u][j];
						path[j] = u;
					}
				}
			}
		}
	}
	
	// 打印路径
	public static void printPath(int u){
		// 如果是0代表到达起点
		if(path[u] == -1){
			System.out.print("路径:"+u+"->");
		}else{
			// 上一层
			printPath(path[u]);
			// 递归结束,打印路径
			System.out.print(u+"->");
		}
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		e = sc.nextInt();
		// 初始化
		G = new int[n + 1][n + 1];
		dis = new int[n + 1];
		path = new int[n + 1];
		visit = new boolean[n + 1];
		// 初始化正无穷
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				G[i][j] = Integer.MAX_VALUE;
			}
		}
		// 路径初始化为正无穷
		for(int i = 0; i < dis.length; i++){
			dis[i] = Integer.MAX_VALUE;
		}
		// 输入边
		int u, v, vl;
		for(int i = 0; i < e; i++){
			u = sc.nextInt();
			v = sc.nextInt();
			vl = sc.nextInt();
			G[u][v] = vl; // 有向有权图
		}
		
		// 从1开始的路径
		dijstrax(1);
		
		// 得到长度
		for(int i = 2; i <= n; i++){
			System.out.print("源点1到点"+i+"的长度:"+dis[i]+",");
			// 打印路径
			printPath(i);
			System.out.println();
		}
		sc.close();
	}
}

2.输入数据
6 8
1 2 2
1 3 1
2 6 6
3 4 2
3 5 10
3 6 2
4 5 3
4 6 1
3.对应的图
在这里插入图片描述

4.输出数据
在这里插入图片描述
5.邻接表表示图

import java.util.ArrayList;
import java.util.Scanner;

public class AdlistDijkstraShoterPath {
	static class Edge{
		int u, v, val;
		public Edge(int u, int v, int val){
			this.u = u;
			this.v = v;
			this.val = val;
		}
	}
	static int n;// 点数
	static int e;// 边数
	static ArrayList<Edge> edgelist;// 边的具体信息
	static ArrayList<Integer> G[];	// 邻接表 G[i] 。G[I] = list:J,K,顶点i的size条边,在edge保存的序号J、K
	static boolean visit[];// 是否访问过的节点
	static int dis[];// 路径 dis[i] = j, 默认1到节点i最短路径j
	static int path[];// 记录路线
	
	// 寻找源点到节点最下的路径节点,并且没有访问过的
	public static int findMinNode(){
		int max = Integer.MAX_VALUE;
		int node = -1;
		for(int i = 1; i <= n; i++){
			if(dis[i] < max && !visit[i]){
				max = dis[i];
				node = i;
			}
		}
		return node;// 如果返回-1代表没找到
	}
	
	// dij
	public static void dijstrax(int yuan){
		// 初始化源点为0代表最小,第一个取出
		dis[yuan] = 0;
		path[yuan] = -1;// 源点记录区分
		int u = 0;
		while(true){
			u = findMinNode();
			// =-1代表都访问过并扩散了,可以退出了
			if(u == -1){
				break;
			}
			// 标记访问了当前节点
			visit[u] = true;
			// 以当前u节点,扩散它的领接点
			for(int j = 0; j < G[u].size(); j++){
				// 从边list中取出具体边信息
				Edge ed = edgelist.get(G[u].get(j));
				// v点没有访问过
				if(!visit[ed.v]){
					// 如果:源点到点u+u点到v点 < 源点到j点 ,就更新
					if(dis[u] + ed.val < dis[ed.v]){
						dis[ed.v] = dis[u] + ed.val;
						path[ed.v] = u;
					}
				}
			}
		}
	}
	
	// 打印路径
	public static void printPath(int u){
		// 如果是0代表到达起点
		if(path[u] == -1){
			System.out.print("路径:"+u+"->");
		}else{
			// 上一层
			printPath(path[u]);
			// 递归结束,打印路径
			System.out.print(u+"->");
		}
	}
	
	// 带权有向图的添加
	public static void insertEdge(int from, int to, int vl){
		edgelist.add(new Edge(from, to, vl));
		// 在edgelist中的下标
		int size = edgelist.size();
		G[from].add(size - 1);// 在edgelist的下标
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		e = sc.nextInt();
		// 初始化
		edgelist = new ArrayList<Edge>();
		G = new ArrayList[n + 1];
		dis = new int[n + 1];
		path = new int[n + 1];
		visit = new boolean[n + 1];
		// 初始化G
		for(int i = 0; i < G.length; i++){
			G[i] = new ArrayList<>();
		}
		// 路径初始化为正无穷
		for(int i = 0; i < dis.length; i++){
			dis[i] = Integer.MAX_VALUE;
		}
		// 输入边
		for(int i = 0; i < e; i++){
			insertEdge(sc.nextInt(), sc.nextInt(), sc.nextInt());
		}
		
		// 从1开始的路径
		dijstrax(1);
		
		// 得到长度
		for(int i = 1; i <= n; i++){
			System.out.print("源点1到点"+i+"的长度:"+dis[i]+",");
			// 打印路径
			printPath(i);
			System.out.println();
		}
		sc.close();
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值