迪杰斯特拉算法详解
说明
- 迪杰斯特拉算法是求解带权无向图中某一顶点到其他顶点的最短路径问题
- 核心思想为定义一个数组保存当前顶点到其他顶点的距离,然后通过广度优先算法,即横向扫描的方式,不断比较不同走法的路径大小,将最小路径对应的权值记录在数组中
- 每次在更新路径时,路径权值应当包含两部分,一是路径数组里边已经存在的路径权值,二是在选择不同路径时当前顶点与目标顶点之间的路径权值,后者通过邻接矩阵即可得到,然后将这两部分的和与路径权值数组里边的权值作比较,将小的继续存储到路径权值数组
- 因为在刚开始的时候,当前顶点到其他顶点的权值都设置为一个较大的数字,表示不通,顶点自己到自己的距离为0
- 还需要一个数组保存顶点是否被访问,如果被访问,则在下次选择路径时不再考虑该节点
- 源码见下
源码及分析
package algorithm.algorithm.dijkstra;
import java.util.Arrays;
/**
* @author AIMX_INFO
* @version 1.0
*/
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);
graph.showGraph();
//迪杰斯特拉算法
graph.dijkstra(6);
graph.show();
}
}
class Graph {
//顶点
private char[] vertex;
//邻接矩阵
private int[][] matrix;
//类属性
private VisitedVertex vv;
public Graph(char[] vertex, int[][] matrix) {
this.vertex = vertex;
this.matrix = matrix;
}
//查看图
public void showGraph() {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.printf("%7d", matrix[i][j]);
}
System.out.println();
}
}
//迪杰斯特拉算法
/**
* @param index 出发顶点对应的下标
*/
public void dijkstra(int index) {
vv = new VisitedVertex(vertex.length, index);
update(index);
for (int i = 1; i < vertex.length; i++) {
int in = vv.updateArr();
update(in);
}
}
/**
* 更新index下标顶点到周围顶点的距离和周围顶点的前驱顶点
*
* @param index
*/
public void update(int index) {
int len = 0;
for (int i = 0; i < matrix[index].length; i++) {
//记录出发顶点到index顶点的和 + 从index到其他顶点的和
len = vv.getDis(index) + matrix[index][i];
//如果另一种走法路径更短
if (!vv.in(i) && len < vv.getDis(i)) {
vv.updatePre(i, index);
vv.updateDis(i, len);
}
}
}
public void show(){
vv.show();
}
}
class VisitedVertex {
//顶点是否被访问过
private int[] already_arr;
//前驱顶点
private int[] pre_visited;
//当前顶点到其他顶点的距离
private int[] dis;
public VisitedVertex(int length, int index) {
already_arr = new int[length];
pre_visited = new int[length];
dis = new int[length];
//设置出发点到其他顶点的位置为最大
Arrays.fill(dis, 65535);
//设置出发点距离自己的距离为 0
dis[index] = 0;
already_arr[index] = 1;
}
//判断index所在的顶点是否被访问过
/**
* @param index 当前顶点所在的位置
* @return 返回是否访问过
*/
public boolean in(int index) {
return already_arr[index] == 1;
}
/**
* 更新出发点到index顶点的距离
*
* @param index 顶点位置
* @param len 距离
*/
public void updateDis(int index, int len) {
dis[index] = len;
}
/**
* 更新pre的前驱顶点为index
*
* @param pre
* @param index
*/
public void updatePre(int pre, int index) {
pre_visited[pre] = index;
}
/**
* 返回出发顶点到index的距离
*
* @param index
* @return
*/
public int getDis(int index) {
return dis[index];
}
//继续选择并访问新的访问顶点
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;
}
}
//更新index已经访问过
already_arr[index] = 1;
return index;
}
//显示结果
public void show(){
for (int i = 0; i < dis.length; i++) {
System.out.print(dis[i] + "\t");
}
}
}