java之迪杰斯特拉算法

java之dijkstra算法


文章内容选自尚硅谷数据结构和算法,eclipse环境,jdk11

算法思想

课程里说,dijkstra算法要具备三个数组,一个数组是already_arr,用来记录已经访问了的结点,另一个数组是dis数组,用来记录出发结点或者访问结点到某结点距离的最短路径。还有一个pre_visited数组,假如说pre_visited[i]=j,说明第i个结点的前驱结点是第j结点。

最后dis数组内的元素就记录了从出发点到其余各结点的最短距离。

我觉得 pre_visited数组在该算法中并没有实际价值,它只能记录最后一轮遍历,各结点的前驱结点是谁,其实在多轮遍历中,前驱结点经常被覆盖。如果把pre_visited改为二维数组,或者链表形式,记录最优路径,则更为恰当。

声明一个概念,出发结点和访问节点,出发结点只有一个,就是最开始遍历的节点,访问节点就是除了出发结点的其他节点,在算法中,如果有n个结点,就要有n-1轮遍历,每一轮遍历都要遍历所有结点,每一轮遍历都是从访问节点开始的。

  • 该算法首先要初始化,选定一个出发结点,然后设置already_arr中出发结点的位置为1,其余全为0;dis数组中该出发结点的距离为0,其余距离都为65535,pre_visited为全0.
  • 随后进行第一轮遍历(此时还并没有进入for循环内部),即执行update函数。这儿有个细节:先设立already_arr出发(访问)结点为1,再进行(for循环内部)update的遍历。这是在dij函数内进行的,dij函数可谓 是主函数。
  • 遍历每完成一轮,选出该轮dis距离中最短的一个位置,把already_arr该位置设置为1,以这个位置作为下次遍历的访问节点,开始下一轮的遍历。对应upgradeArr函数
  • 遍历的过程中,运用到了动态规划的思想,这一点难以说明,其最重要的语句莫过于update函数中的
			int len = vv.getDis(index) + matrix[index][i]; //访问结点的路径长度加上访问结点到其他结点的路径长度
			if(!vv.isVisited(i) && len < vv.dis[i]) {
				vv.setDis(i, len);
				vv.setPre(i, index);
			}

意思是说如果出发(访问)结点记录的dis距离加上出发(访问)结点到i结点的距离,短于此时dis数组中记录i结点的距离,说明找到了一条更优的路径,短于当前记录i的距离(当前出发结点到i的距离),因此进行更新。之所以说用到了动态规划dp算法,是因为每一轮的更新,都用到了上一轮dis记录的信息。

代码演示

package com.atguigu.dijkstra;

import java.util.Arrays;

public class DijkstraAlgorithm {

	public static void main(String[] args) {
		char[] vertex = {'A','B','C','D','E','F','G'};
		int matrix[][] = new int[vertex.length][vertex.length];
		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 graph =  new Graph(vertex,matrix,2);
		graph.showGraph(matrix);
		graph.dij(2);
		graph.showRes();
	}

}

class Graph{
	private char[] vertex;
	private int[][] matrix;
	private VisitedVertex vv;
	
	public Graph(char[] vertex,int matrix[][],int index) {
		this.vertex = vertex;
		this.matrix = matrix;
		vv = new VisitedVertex(vertex.length,index);
	}
	
	public void showGraph(int[][] matrix) {
		for(int[] tmp:matrix) {
			System.out.println(Arrays.toString(tmp));
		}
	}
	
	public void update(int index) {
		for(int i = 0;i < vertex.length;i++) {
			int len = vv.getDis(index) + matrix[index][i]; //访问节点的路径长度加上访问节点到其他结点的路径长度
			if(!vv.isVisited(i) && len < vv.dis[i]) {
				vv.setDis(i, len);
				vv.setPre(i, index);
			}
		}
	}
	
	public void dij(int index) {
		update(index);
		for(int i = 1;i<vertex.length;i++) {
			int id = vv.upgradeArr();
			update(id);
		}
	}
	
	public void showRes() {
		vv.showRes();
	}
}

class VisitedVertex{
	private int already_arr[];
	private int pre_visited[];
	int dis[];
	
	public VisitedVertex(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);
		dis[index] = 0;
		already_arr[index] = 1;
	}
	
	public int getDis(int index) {
		return dis[index];	
	}
	
	public boolean isVisited(int index) {
		return already_arr[index] == 1;
	}
	
	public int upgradeArr() {
		int index=0;
		int min = 65535;
		for(int i = 0;i < dis.length;i++) {
			if(already_arr[i] == 0 && dis[i] < min) {
				min = dis[i];
				index = i;
			}
		}
		already_arr[index] = 1;
		return index;
	}
	
	public void setDis(int index,int len) {
		dis[index] = len;
	}
	
	public void setPre(int pre,int index) {
		pre_visited[pre] = index;
	}
	
	public void showRes() {
		System.out.println("======================================");
		System.out.println("already_arr" + Arrays.toString(already_arr));
		System.out.println("pre_visited" + Arrays.toString(pre_visited));
		System.out.println("dis" + Arrays.toString(dis));
		char[] vertex = {'A','B','C','D','E','F','G'};
		int count = 0;
		for(int i:dis) {
			System.out.printf(vertex[count] + "(" + dis[count] + ")" + "\t");
			count++;
		}
	}
}

演示结果为

[65535, 5, 7, 65535, 65535, 65535, 2]
[5, 65535, 65535, 9, 65535, 65535, 3]
[7, 65535, 65535, 65535, 8, 65535, 65535]
[65535, 9, 65535, 65535, 65535, 4, 65535]
[65535, 65535, 8, 65535, 65535, 5, 4]
[65535, 65535, 65535, 4, 5, 65535, 6]
[2, 3, 65535, 65535, 4, 6, 65535]
======================================
already_arr[1, 1, 1, 1, 1, 1, 1]
pre_visited[2, 0, 0, 5, 2, 4, 0]
dis[7, 12, 0, 17, 8, 13, 9]
A(7) B(12) C(0) D(17) E(8) F(13) G(9)

如果改为从G位置为出发结点,则同时设置设置初始化 Graph graph = new Graph(vertex,matrix,6);dij(6)

		Graph graph =  new Graph(vertex,matrix,6);
		graph.showGraph(matrix);
		graph.dij(6);
		graph.showRes();

运行结果为

[65535, 5, 7, 65535, 65535, 65535, 2]
[5, 65535, 65535, 9, 65535, 65535, 3]
[7, 65535, 65535, 65535, 8, 65535, 65535]
[65535, 9, 65535, 65535, 65535, 4, 65535]
[65535, 65535, 8, 65535, 65535, 5, 4]
[65535, 65535, 65535, 4, 5, 65535, 6]
[2, 3, 65535, 65535, 4, 6, 65535]
======================================
already_arr[1, 1, 1, 1, 1, 1, 1]
pre_visited[6, 6, 0, 5, 6, 6, 0]
dis[2, 3, 9, 10, 4, 6, 0]
A(2) B(3) C(9) D(10) E(4) F(6) G(0)

Ps:我复现的代码不够简洁,在变换出发结点时需要改两处,而视频源码只需改一处,即直接把VisitedVertex对象的建立放在dij函数中,就实现了只改dij函数即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值