优先队列实现有向图的迪杰斯特拉

package ccf;

import java.util.ArrayList;

import java.util.Comparator;

import java.util.PriorityQueue;

import java.util.Queue;

import java.util.Scanner;



public class  PriorityQueueDijstra  {

 

	/**

	 * 应用优先队列优化dijkastra解决单源点最短路径问题

	 * @param args

	 */

	static class node{

		public int nod;//节点标号

		public int sum;//当前nod节点到源点的最小的距离

		node(int nod,int sum){

			this.nod=nod;

			this.sum=sum;

		}

	}

	//邻接表节点

	static class edge{

		public int a;//起始节点

		public int b;//结束节点

		public int w;

		edge(int a,int b,int w){

			this.a=a;

			this.b=b;

			this.w=w;

		}

	}

	static final int INF=Integer.MAX_VALUE;

	static int vis[];//标记数组

	static int dis[];//dis[i]的意义是节点i到 源点 的最短路径,整个过程就是在维护这个数组

	public static void main(String[] args) {

		Scanner sc=new Scanner(System.in);

		int start=sc.nextInt();//起始点位置

		int n=sc.nextInt();//图的节点个数

		int m=sc.nextInt();//边数

//		sc.nextLine();

//		int map[][]=new int[n+1][n+1];//邻接矩阵

		//初始化邻接矩阵都为INF

//		for (int i = 0; i < map.length; i++) {

//			for (int j = 0; j < map[0].length; j++) {

//				map[i][j]=INF;

//			}

//		}

		//邻接表

		ArrayList<edge>[] map=new ArrayList[n+1];

		for (int i = 0; i < map.length; i++) {

			map[i]=new ArrayList<edge>();

		}

		//将数据录入邻接矩阵

		for (int i = 0; i < m; i++) {

			int a=sc.nextInt();

			int b=sc.nextInt();

			int w=sc.nextInt();

			map[a].add(new edge(a,b,w));
			
			//map[b].add(new edge(b,a,w));

			//邻接矩阵方法

//			map[a][b]=Math.min(map[a][b],w);//可能会有两个节点间存在两条路径,总是选取最小的那条

		}

		//执行算法
		
		dijkstra(start,map,n,m);

		

		for (int i = 1; i < dis.length; i++) {

			System.out.println(dis[i]);

		}

	}

	/**

	 * 

	 * @param start 初始节点

	 * @param map 邻接矩阵

	 * @param n 节点数量

	 * @param m 边的数量

	 */

	private static void dijkstra(int start, ArrayList<edge>[] map, int n, int m) {

		//重写comparator方法,规定队列中小的数优先出队

		Comparator<node> com=new Comparator<node>(){

			@Override

			public int compare(node o1, node o2) {

				int num1=o1.sum;

				int num2=o2.sum;

				if(num1>num2){

					return 1;   //返回1代表num1在后,即大数在后,从小到大排序

				}else if (num1<num2) {

					return -1;  //返回-1代表num1在前,即小数在前,从小到大排序

				}else {

					return 0;  //返回0 表示位置不变

				}

			}
/***
 * 
 * 			public int compare(node o1, node o2) {

				int num1=o1.sum;

				int num2=o2.sum;

				if(num1<num2){

					return 1;   //返回1代表num1在后,即小数在后,从大到小排序

				}else if (num1>num2) {

					return -1;  //返回-1代表num1在前,即大数在前,从大到小排序

				}else {

					return 0;  //返回0 表示位置不变

				}

			}
 */
		};

		//定义优先队列,初始值为11,比较器为com

		Queue<node> q=new PriorityQueue<node>(11,com);//初始化优先队列

		q.offer(new node(start,0));//初始节点入队

		vis=new int[n+1];//初始化 标记表

		dis=new int[n+1];//初始化 各节点到源点的最小距离表

		//都初始化为INF

		for (int i = 0; i <= n; i++) {

			dis[i]=INF;

		}

		//start节点到自身的距离为0

		dis[start]=0;

		while (q.size()!=0) {//当优先队列不为空时

			node temp=q.poll();//弹出并删除队列头结点

			int t=temp.nod;//提取头节点下表数

			if(vis[t]==1){//如果该节点已经被访问过了,直接跳过这次循环

				continue;

			}

			vis[t]=1;//没有访问过,标记访问过

			//遍历所有t的邻接节点

			for (int i = 0; i < map[t].size(); i++) {

				//如果该节点没有被访问过,且,tempnode到能够到达该节点(邻接)

				if(vis[map[t].get(i).b]==0 && map[t].get(i).w<INF){

					//松弛操作,更新dis表,如果这个邻接节点map[t].get(i).b到原地的距离要  大于  当前节点t到原点的距离+t节点到他的邻接点map[t].get(i).b 的距离之和

					if(dis[map[t].get(i).b]>dis[t]+map[t].get(i).w){

						dis[map[t].get(i).b]=dis[t]+map[t].get(i).w;//更新邻接点map[t].get(i).b到远点的距离

						q.offer(new node(map[t].get(i).b,dis[map[t].get(i).b]));//将更新的节点压入优先队列

					}

				}

			}

		}

	}

}

在dij算法中dis[i]数组表达的意义是:节点i到源点start最短距离,松弛操作dis[i]>dis[t]+map[t][i](t节点是最新确定的最短路径节点,i节点既是t的一个邻接节点)的意义是:t的邻接节点i到源点start的最小距离(dis[i]),是否大于 最新节点t到原点的最短距离(dis[t])+节点t与节点i的权值(map[t][i]),这一过程都在围绕dis[i]数组进行。在dij算法中dis[i]数组表达的意义是:节点i到源点start最短距离,松弛操作dis[i]>dis[t]+map[t][i](t节点是最新确定的最短路径节点,i节点既是t的一个邻接节点)的意义是:t的邻接节点i到源点start的最小距离(dis[i]),是否大于 最新节点t到原点的最短距离(dis[t])+节点t与节点i的权值(map[t][i]),这一过程都在围绕dis[i]数组进行。

原文:https://blog.csdn.net/qq_39020387/article/details/79979543 
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值