一、什么是迪杰斯特拉算法?
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法策略,广度优先思想,一步一步算出距离起始点最近且未访问过的顶点,直至所有顶点都被访问最终可得出起始点到所有顶点的最短路径。
二、实现步骤
本代码使用永久和临时标号方式来实现。
1、初始化起始点到其他顶点的路径及权值,不存在边的权值为0。
2、选出当前距离起始点权值最小的顶点,总权值为0和永久顶点除外,标记当前选中的顶点为永久顶点。
3、根据步骤2⃣️选出的顶点,遍历它的直接临界点,如果起始点到当前遍历顶点的总权值比之前统计的总权值小,则更新起始点到该顶点的路径及权值。
4、重复步骤2⃣️3⃣️,直至所有顶点全部遍历完成。
三、实现代码
代码如下(示例):
public class Test {
/**
* 所有端点名称
*/
private static final String[] ENDPOINT_NAMES;
/**
* 端点矩阵 图
*/
private static final int[][] GRAPH;
/**
* 起点 下标
*/
private static final int START_ENDPOINT_INDEX;
static {
ENDPOINT_NAMES = new String[]{"V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7", "V8"};
GRAPH = new int[9][9];
for (int i = 0; i < GRAPH.length; i++) {
for (int j = 0; j < GRAPH[i].length; j++) {
if (i == j) {
GRAPH[i][j] = 0;
} else {
GRAPH[i][j] = -1;
}
}
}
GRAPH[0][1] = 1;
GRAPH[1][0] = 1;
GRAPH[0][2] = 5;
GRAPH[2][0] = 5;
GRAPH[1][2] = 3;
GRAPH[2][1] = 3;
GRAPH[1][3] = 7;
GRAPH[3][1] = 7;
GRAPH[1][4] = 5;
GRAPH[4][1] = 5;
GRAPH[2][4] = 1;
GRAPH[4][2] = 1;
GRAPH[2][5] = 7;
GRAPH[5][2] = 7;
GRAPH[4][3] = 2;
GRAPH[3][4] = 2;
GRAPH[6][3] = 3;
GRAPH[3][6] = 3;
GRAPH[4][6] = 6;
GRAPH[6][4] = 6;
GRAPH[4][7] = 9;
GRAPH[7][4] = 9;
GRAPH[4][5] = 3;
GRAPH[5][4] = 3;
GRAPH[5][7] = 5;
GRAPH[7][5] = 5;
GRAPH[6][7] = 2;
GRAPH[7][6] = 2;
GRAPH[6][8] = 7;
GRAPH[8][6] = 7;
GRAPH[7][8] = 4;
GRAPH[8][7] = 4;
//随机选择起点、终点
Random random = new Random();
START_ENDPOINT_INDEX = random.nextInt(ENDPOINT_NAMES.length - 1);
}
public static void main(String[] args) {
ShortestPath[] shortestPaths = init(GRAPH[START_ENDPOINT_INDEX]);
List<Integer> visitedEndPointIndexList = new ArrayList<>(shortestPaths.length);
visitedEndPointIndexList.add(START_ENDPOINT_INDEX);
selectAndUpdateShortestPath(shortestPaths, visitedEndPointIndexList);
for (int i = 0; i < shortestPaths.length; i++) {
if (i == START_ENDPOINT_INDEX) {
continue;
}
ShortestPath temp = shortestPaths[i];
System.out.print(ENDPOINT_NAMES[START_ENDPOINT_INDEX] + "到" + ENDPOINT_NAMES[i] + "最短权值为:" + temp.getTotalWeight() + " ");
List<EndPoint> pathList = temp.getLinkedList();
for (EndPoint endPoint : pathList) {
System.out.print(endPoint.getName() + "->");
}
System.out.println();
}
}
/**
* 筛选当前离源点最近的端点并且更新原点到其他端点的最短路径
* 时间复杂度 n的平方,n为端点数
*
* @param shortestPaths
* @param visitedEndPointIndexList
*/
private static void selectAndUpdateShortestPath(ShortestPath[] shortestPaths, List<Integer> visitedEndPointIndexList) {
int minWeight = Integer.MAX_VALUE;
ShortestPath minShortestPath = null;
int nextIndex = -1;
for (int i = 0; i < shortestPaths.length; i++) {
ShortestPath temp = shortestPaths[i];
int weight = temp.getTotalWeight();
if (weight == 0) {
continue;
}
if (visitedEndPointIndexList.contains(i)) {
continue;
}
if (weight < minWeight) {
nextIndex = i;
minWeight = weight;
minShortestPath = temp;
}
}
if (nextIndex == -1) {
return;
}
visitedEndPointIndexList.add(nextIndex);
int[] nextSearch = GRAPH[nextIndex];
for (int i = 0; i < nextSearch.length; i++) {
int weight = nextSearch[i];
if (weight == -1 || nextIndex == i || visitedEndPointIndexList.contains(i)) {
continue;
}
int totalWeight = minShortestPath.getTotalWeight() + weight;
ShortestPath currentPath = shortestPaths[i];
int currentTotalWeight = currentPath.getTotalWeight();
// 更新最短路径
if (currentTotalWeight > totalWeight || currentTotalWeight == 0) {
LinkedList<EndPoint> linkedList = new LinkedList<>();
linkedList.addAll(minShortestPath.getLinkedList());
linkedList.add(new EndPoint(ENDPOINT_NAMES[i], weight));
shortestPaths[i] = new ShortestPath(totalWeight, linkedList);
}
}
selectAndUpdateShortestPath(shortestPaths, visitedEndPointIndexList);
}
/**
* 初始化 源点到其他端点的路径
*
* @param array
* @return
*/
private static ShortestPath[] init(int[] array) {
ShortestPath[] shortestPaths = new ShortestPath[array.length];
ShortestPath currentPointPath;
List<EndPoint> linkedList;
EndPoint endPoint;
for (int i = 0; i < array.length; i++) {
int weight = array[i];
linkedList = new LinkedList();
endPoint = new EndPoint(ENDPOINT_NAMES[START_ENDPOINT_INDEX], 0);
linkedList.add(endPoint);
currentPointPath = new ShortestPath(0, linkedList);
shortestPaths[i] = currentPointPath;
// 说明没边
if (weight == -1) {
continue;
}
endPoint = new EndPoint(ENDPOINT_NAMES[i], weight);
linkedList.add(endPoint);
currentPointPath.setTotalWeight(currentPointPath.getTotalWeight() + weight);
}
return shortestPaths;
}
}
@Data
@AllArgsConstructor
class EndPoint {
/**
* 端点名称
*/
private String name;
/**
* 权值
*/
private Integer weight;
}
@Data
@AllArgsConstructor
class ShortestPath {
/**
* 路径总权值
*/
private Integer totalWeight;
/**
* 路径
*/
private List<EndPoint> linkedList;
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了狄迪斯特拉的算法的原理及实现.由于它遍历计算的节点很多,所以效率低,可以自行根据其他数据结构进行优化。