Dijikstra算法的具体实现


title: Dijikstra算法实现
date: 2020-04-09 23:04:09

Dijikstra算法是图论里面的经典算法,用来算某一源点到其他各个点的最短路径的问题。


算法的步骤

1.准备工作:
(1).首先设置一个顶点集和S记录已经求得的最短路径的点集合,V初始时所有点的集和,初始时把源点v0从V中放入S,集和S每次加入一个新的点vi,都要更新v0到V-S中各点的最短路径值
(2).设置一个distance数组用于记录源点到当前点的最短路径值(distance[i]表示源点到i号节点的最短路径)
(3).设置一个pronode数组用于存放源点到当前节点时要经过的i的前驱节点(例如:0到3的最短路径是0-1-2-3;则distan[3]=2)用来在算法结束后根据数组找到他的最短路径信息
(4).邻接矩阵weight[i][j]表示从i节点到j节点的权重,如果存在i到j的边则weight[i][j]为边权重,否则其值为∞
2.实现步骤:
(1)初始化:集和S初始为{0},distance[]的初始值distance[i]=weight[0][i],i=1,2…n-1
(2)从顶点集和V-S中选出vj满足vj=min{distance[i]|vi∈(V-S)} (就是从未确定最短路径的点集合中,选出离源点最近的那个点,这里就是贪心的思想),此时vj就是当前求得的一条从v0出发的最短路径的终点,把vj加入到已知最短路径的点集合S中去:S=S U{j}
(3)修改从v0出发到集和(V-S)上任一点vk的最短路径值,如果distance[j]+weight[j][k]<distance[k],那就把distance[k]更新为distance[j]+weight[j][k],(意思是从v0到vk在不经过vj的情况下距离大于v0通过vj到vk的距离时,松弛他),
(4)重复2~3操作共n-1次


举例如下图:在这里插入图片描述

顶点第一轮第二轮第三轮第四轮
210 (v1-v2)8 (v1-v5-v2)8 (v1-v5-v2) √
314 (v1-v5-v3)13 (v1-v5-v4-v3)9 {v1-v5-v2-v3} √
47 (v1-v5-v4) √
55(v1-v5) √
集和S{1,5}{1,5,4}{1,5,4,2}{1,5,4,2,3}

执行过程:
初始化(第一轮):集和S为{v1},v1到v2,v5可达,到v3,v4不可达,因此distance数组为dista[2]=10,distance[5]=5;distance[3]=distance[4]=∞;选出最小的distace[5]将5号节点加入S中。
第二轮:根据新加入的节点5,更新distance数组(只更新未被加入S中的点)distance[3]=∞,distance[5]+weight[5][3]<distance[3],故更新distance[3]=distance[5]+weight[5][3] ;同理更新distance[2]=min(distance[2],distance[5]+weight[5][2]),distance[4]=min(distance[4],distance[5]+weight[5][4]);选出最短路径点v4 把4号节点放入S中。
第三轮:根据新加入的节点4,更新distance数组;distance[2]=min(distance[2],distance[4]+weight[4][2]),distance[3]=min(distance[3],distance[3]+weight[4][3]);
第四轮:根据新加入的节点2更新distance数组distance[3]=min(distance[3],distance[2]+weight[2][3])=9.


为什么Dijikstra算法时不允许有负权重的?
如果存在负权重,则S里面的某个点a以负权重相连的b点确定其最短路径时如果存在负权重,则S里面的某个点a与以负权重相连的b点确定其最短路径时,可能存在经过负权重后的路径才是最短路径,但此时a已经在S中无法在继续更新
如下两种情况都会导致Dijikstra算法失效
在这里插入图片描述
对于情况1,以1为源点,把节点3加入后,当再加入节点2时,原来的S里已经有节点3,但此时0-2-3才是最短路径,但无法更新0-3的距离。
对于情况2,存在负回路,就不存在最短路径。


实现的代码如下:参考链接: 参考

	import java.util.LinkedList;
	import java.util.Stack;
	class Edge1{
		private int v1;
		private int v2;
		private int weight;
		public Edge1(int v1,int v2,int weight){
			this.v1=v1;
			this.v2=v2;
			this.weight=weight;
		}
		public int getV1(){
			return v1;
		}

		public int getV2(){
			return v2;
		}
		public int getWeight(){
			return  weight;
		}
		public boolean equals(Edge1 edge){
			return this.v1==edge.getV1()&&this.v2==edge.getV2()&&this.weight==edge.getWeight();
		}

		public String toString(){
			String str="["+v1+","+v2+","+weight+"]";
			return str;
		}
	}
		
	class Graph1{
		private LinkedList<Edge1>[] edgeLinks;//顶点的边的集和
		private int vNum;       //顶点总数
		private int edgeNum;    //边总数
		private int[] distance;   //存放远点到i点距离
		private int[] prenode;
		private LinkedList<Integer> S;   //已知的最短路径的点集和
		private LinkedList<Integer> Q;      //不确定的最短路径的点集和
		public static final int INF=10000;    //无穷大
		public static final int NIL=-1;      //不存在

		public Graph1(int vNum){
			this.vNum=vNum;
			edgeLinks=new LinkedList[vNum];
			edgeNum=0;
			distance=new int[vNum];
			prenode=new int[vNum];
			for(int i=0;i<vNum;i++)
				edgeLinks[i]=new LinkedList<>();   //每一个顶点new一个以他作为其起始点的边集和
		}

		public void insertEdge(Edge1 edge){
			int v1=edge.getV1();
			edgeLinks[v1].add(edge);   //给以点v1为起始点的边的集和里加入edge这条边
			edgeNum++;
		}

		public void travel(){
			System.out.println("共有:"+vNum+"个顶点,"+edgeNum+" 条边");
			for (int i=0;i<vNum;i++){
				LinkedList<Edge1> list=(LinkedList<Edge1>)edgeLinks[i].clone();
				while (!list.isEmpty()){
					Edge1 edge=list.pop();
					System.out.println(edge.toString());
				}
			}
		}

		/**
		 * 对最短路径估计和前驱节点初始化
		 */
		public void Init_Single_Source(int start){
			for (int i=0;i<vNum;i++){
				distance[i]=INF;
				prenode[i]=NIL;
			}
			distance[start]=0;
		}

		public void relax(Edge1 edge){
			int v1=edge.getV1();
			int v2=edge.getV2();
			int w=edge.getWeight();
			if(distance[v2]>distance[v1]+w){
				distance[v2]=distance[v1]+w;
				prenode[v2]=v1;
			}
		}


		public int ECTRACT_MIN(LinkedList<Integer> q){
			if(q.isEmpty())
				return -1;
			int min=q.getFirst();
			for(int i=0;i<q.size();i++){
				int v=q.get(i);
				if(distance[min]>distance[v])
					min=v;
			}
			q.remove(q.indexOf(min));
			return min;
		}

		public void Dijistra(int start){
			Init_Single_Source(start);
			S=new LinkedList<>();
			Q=new LinkedList<>();
			for (int i=0;i<vNum;i++)    //将所有开始的点集加入到Q中
				Q.add(i);
			while (!Q.isEmpty()){
				int v=ECTRACT_MIN(Q);
				S.add(v);
				LinkedList<Edge1> list=(LinkedList<Edge1>)edgeLinks[v].clone();
				while (!list.isEmpty()){
					Edge1 edge1=list.pop();
					relax(edge1);
				}
				showResult();
			}
		}

		public void showResult(){
			System.out.println("-----------------result-------------------");
			Stack<Integer>[] routes=new Stack[vNum];
			for (int i=0;i<vNum;i++){
				routes[i]=new Stack<>();
				int j=i;
				while (j!=NIL){
					routes[i].push(j);
					j=prenode[j];
				}

				System.out.print(i+"("+distance[i]+"): ");
				while (!routes[i].isEmpty()){
					int k=routes[i].pop();
					System.out.print("-->"+k);
				}
				System.out.println();
			}
		}

	}

	public class Dijkstra {
		public static void main(String[] args){
			int vnum=5,edgeNum=10;
			Graph1 graph1=new Graph1(vnum);
			Edge1[] edge1s=new Edge1[edgeNum];
			edge1s[0]=new Edge1(0,1,10);
			edge1s[1]=new Edge1(0,3,5);
			edge1s[2]=new Edge1(1,2,1);
			edge1s[3]=new Edge1(1,3,2);
			edge1s[4]=new Edge1(2,4,4);
			edge1s[5]=new Edge1(3,1,3);
			edge1s[6]=new Edge1(3,2,9);
			edge1s[7]=new Edge1(3,4,2);
			edge1s[8]=new Edge1(4,0,7);
			edge1s[9]=new Edge1(4,2,6);
			for (int i=0;i<edgeNum;i++)
				graph1.insertEdge(edge1s[i]);
			graph1.travel();
			graph1.Dijistra(0);
		   // graph1.Dijistra(4);
		}
	}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值