迪杰斯特拉算法

定义

迪杰斯特拉算法用于计算图中,某一个顶点vi到另外一个顶点vj的最短路径,因为计算从vi到vj的最短路径实际需要计算出vi到vj之前的所有顶点的最短路径,所以实际的计算可能会附带得出vi到图中一部分节点的最短路径,而且这种“附带”的结果是必需的。

算法过程如下:

设置出发顶点为v,顶点集合V{v1,v2,vi...},v到V中各顶点的距离构成距离集合Dis,Dis{d1,d2,di...},Dis集合记录着v到图中各顶点的距离(到自身可以看作0,v到vi距离对应为di)

1、从Dis中选择值最小的di并移出Dis集合,同时移出V集合中对应的顶点vi,此时的v到vi即为最短路径。

2、更新Dis集合,更新规则为:比较v到V集合中顶点的距离值,与v通过vi到V集合中顶点的距离值,保留值较小的一个(同时也应该更新顶点的前驱节点为vi,表明是通过vi到达的)。

3、重复执行两步骤,直到最短路径顶点为目标顶点即可结束。

示例


给{A,B,C,D,E,F,G}对应序号为{0,1,2,3,4,5,6},演示从G顶点,即序号6到图中各顶点的最短路径。

=======================================

最短路径:G

顶点前驱:G->A,G->B,G->E,G->F

到各顶点距离:A:2,B:3,E:4,F:6

=======================================

最短路径:A

顶点前驱:G->A,G->B,G->E,G->F

到各顶点距离:A:2,B:3,C:9,E:4,F:6

=======================================

最短路径:A,B

顶点前驱:G->A,G->B,B->D,G->E,G->F

到各顶点距离:A:2,B:3,C:9,D:12,E:4,F:6

=======================================

最短路径:A,B,E

顶点前驱:G->A,G->B,B->D,G->E,G->F

到各顶点距离:A:2,B:3,C:9,D:12,E:4,F:6

=======================================

最短路径:A,B,E,F

顶点前驱:G->A,G->B,F->D,G->E,G->F

到各顶点距离:A:2,B:3,C:9,D:10,E:4,F:6

=======================================

最短路径:A,B,C,E,F

顶点前驱:G->A,G->B,A->C,F->D,G->E,G->F

到各顶点距离:A:2,B:3,C:9,D:10,E:4,F:6

=======================================

最短路径:A,B,C,D,E,F

顶点前驱:G->A,G->B,A->C,F->D,G->E,G->F

到各顶点距离:A:2,B:3,C:9,D:10,E:4,F:6

参考代码

class t{  
    public static void main(String[] args){  
        char[] vertex=new char[]{'A','B','C','D','E','F','G'}; //顶点数组  
        int[][] matrix=new int[7][];     //邻接矩阵  
        final int N=65535;  
        matrix[0]=new int[]{N,5,7,N,N,N,2};  
        matrix[1]=new int[]{5,N,N,9,N,N,3};  
        matrix[2]=new int[]{7,N,N,N,8,N,N};  
        matrix[3]=new int[]{N,9,N,N,N,4,N};  
        matrix[4]=new int[]{N,N,8,N,N,5,4};  
        matrix[5]=new int[]{N,N,N,4,5,N,6};  
        matrix[6]=new int[]{2,3,N,N,4,6,N};  
        Graph G=new Graph(vertex,matrix);  //构建图对象  
        //上述为测试用例  
        G.dsj(6);
    }  
}  
class Graph{
	private char[] vertex; //顶点数组
	private int[][] matrix;	//邻接矩阵
	private Visited_vertex vi;	//已访问的顶点集合
	public Graph(char[] vertex,int[][] matrix){
		this.vertex=vertex;
		this.matrix=matrix;
	}
	public void dsj(int index){	//迪杰斯特拉算法计算最短路径
		vi=new Visited_vertex(vertex.length,index);//初始化访问顶点集合对象
		update(index);//更新index下标顶点到周围顶点的距离与周围顶点的前驱顶点
		vi.show();//查看中间过程
		for(int j=1;j<vertex.length;j++){
			index=vi.updateArr();//选择并返回新的访问顶点
			update(index);//更新从出发顶点到index周围各顶点的距离
			vi.show();
		}
	}
	private void update(int index){//更新从出发顶点到index周围各顶点的距离
		int len=0;
		for(int j=0;j<matrix[index].length;j++){
			/*下面这个判断条件是指:j顶点还没有被访问,并且从出发顶点到index顶点的距离,加上
			从index顶点到j顶点的距离,小于从出发顶点到j顶点的距离	*/
			len=vi.getDis(index)+matrix[index][j];
			if(!vi.in(j)&&len<vi.getDis(j)){
				vi.updatePre(j,index);//更新j顶点的前驱为index节点
				vi.updateDis(j,len);//更新出发节点到j顶点的距离
			}
		}
	}
}
class Visited_vertex{	//已访问顶点集合
	public int[] already_arr;//已访问则对应下标上赋值为1,默认为0
	public int[] pre_visited;	//每个下标对应的存储值为前一个顶点下标
	public int[] dis;	//记录出发顶点到其他所有顶点的距离
	public Visited_vertex(int length,int index){
		this.already_arr=new int[length];
		this.pre_visited=new int[length];
		this.dis=new int[length];
		Arrays.fill(dis,65535);//设置初始距离
		already_arr[index]=1;//设置出发顶点为已访问
		dis[index]=0;//设置出发顶点访问距离为0
	}
	public int updateArr(){//选择并返回新的访问顶点
		int min=65535,index=0;;
		for(int i=0;i<already_arr.length;i++){
			if(already_arr[i]==0&&dis[i]<min){
				min=dis[i];
				index=i;
			}
		}
		already_arr[index]=1;
		return index;
	}
	public boolean in(int index){//判断index顶点是否被访问过
		return already_arr[index]==1;
	}
	public void updateDis(int index,int len){//更新出发节点到j顶点的距离
		dis[index]=len;
	}
	public void updatePre(int pre,int index){//更新j顶点的前驱为index节点
		pre_visited[pre]=index;
	}
	public int getDis(int index){//返回从出发顶点到index顶点的距离
		return dis[index];
	}
	public void show(){
		System.out.println("=============================");
		for(int i:already_arr){
			System.out.print(i+"  ");
		}
		System.out.println();
		for(int i:pre_visited){
			System.out.print(i+"  ");
		}
		System.out.println();
		for(int i:dis){
			if(i!=65535){
				System.out.print(i+"  ");
			}else{
				System.out.print("N  ");
			}
		}
		System.out.println();
	}
}

测试结果

E:\>java t
=============================
0  0  0  0  0  0  1	      序号为1表示已访问过,标记作为已到达最短路径
6  6  0  0  6  6  0	      表示对应下标的顶点的前驱顶点,如6表示G,A(0),B(1),E(4),F(5)前驱都是G(6)
2  3  N  N  4  6  0	      表示出发顶点G到各下标的顶点的距离,A(0)为2,B(1)为3
=============================
1  0  0  0  0  0  1
6  6  0  0  6  6  0
2  3  9  N  4  6  0
=============================
1  1  0  0  0  0  1
6  6  0  1  6  6  0
2  3  9  12  4  6  0
=============================
1  1  0  0  1  0  1
6  6  0  1  6  6  0
2  3  9  12  4  6  0
=============================
1  1  0  0  1  1  1
6  6  0  5  6  6  0
2  3  9  10  4  6  0
=============================
1  1  1  0  1  1  1
6  6  0  5  6  6  0
2  3  9  10  4  6  0
=============================
1  1  1  1  1  1  1
6  6  0  5  6  6  0
2  3  9  10  4  6  0

总结

迪杰斯特拉算法计算最短路径,可以近似看做从出发顶点向外“推进”的过程,也就是距离值一直在变大,直到推动目标顶点。以一个记录前驱顶点下标的数组来表示路径,例如从G顶点,即序号下标为6的顶点出发,路径数组值为{6,6,0,5,6,6,0},则计算G到D的最短路径,D(序号:3)的前驱为F(序号:5),F前驱为G(序号:6),可知由G到D的最短路径为:G->F->D。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值