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] (4)重复2~3操作共n-1次


举例如下图:Dijikstra算法的具体实现_第1张图片

顶点 第一轮 第二轮 第三轮 第四轮
2 10 (v1-v2) 8 (v1-v5-v2) 8 (v1-v5-v2) √
3 14 (v1-v5-v3) 13 (v1-v5-v4-v3) 9 {v1-v5-v2-v3} √
4 7 (v1-v5-v4) √
5 5(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] 第三轮:根据新加入的节点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算法失效
Dijikstra算法的具体实现_第2张图片
对于情况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[] edgeLinks;//顶点的边的集和
		private int vNum;       //顶点总数
		private int edgeNum;    //边总数
		private int[] distance;   //存放远点到i点距离
		private int[] prenode;
		private LinkedList S;   //已知的最短路径的点集和
		private LinkedList 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();   //每一个顶点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 list=(LinkedList)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;idistance[v1]+w){
				distance[v2]=distance[v1]+w;
				prenode[v2]=v1;
			}
		}


		public int ECTRACT_MIN(LinkedList q){
			if(q.isEmpty())
				return -1;
			int min=q.getFirst();
			for(int i=0;idistance[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 list=(LinkedList)edgeLinks[v].clone();
				while (!list.isEmpty()){
					Edge1 edge1=list.pop();
					relax(edge1);
				}
				showResult();
			}
		}

		public void showResult(){
			System.out.println("-----------------result-------------------");
			Stack[] routes=new Stack[vNum];
			for (int i=0;i();
				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

你可能感兴趣的:(算法,java基础编程,算法)