java实现Dijkstra算法
解决的问题: 求解单源最短路径,即各个节点到达源点的最短路径或权值考察其他所有节点到远点的最短路径和长度局限性: 无法解决权值为负数的情况参数:Dijkstra算法步骤:(1)初始化:顶点集S: 顶点A到自已的最短路径长度为0。只包含源点,即S={A}顶点集U: 包含除v0外的其他顶点. 即U={B,C,D,E,F}dist[]:源点还不能到达的节点,其权值为∞path[]:记录当前节点的前驱节点
一.Dijkstra算法想解决的问题
解决的问题: 求解单源最短路径,即各个节点到达源点的最短路径或权值
考察其他所有节点到源点的最短路径和长度
局限性: 无法解决权值为负数的情况
二. Dijkstra算法理论
参数:
S | 记录当前已经处理过的源点到最短节点 |
U | 记录还未处理的节点 |
dist[] | 记录各个节点到起始节点的最短权值 |
path[] | 记录各个节点的上一级节点(用来联系该节点到起始节点的路径) |
Dijkstra算法步骤:
(1)初始化:
顶点集S: 节点A到自已的最短路径长度为0。只包含源点,即S={A}
顶点集U: 包含除A外的其他顶点. 即U={B,C,D,E,F}
dist[]: 源点还不能到达的节点,其权值为∞
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
dist[]: | 0 | 1 | 2 | 3 | 4 | 5 |
初始化值: | 0 | 6 | 3 | ∞ | ∞ | ∞ |
path[]: 记录当前节点的前驱节点下标(源点还不能到达的节点为-1)
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
path[]: | 0 | 1 | 2 | 3 | 4 | 5 |
初始化值: | 0 | 0 | 0 | -1 | -1 | -1 |
(2)从U中选取一个节点,它是源点A到U集中最短路径长度最小的节点,如上述为C
然后把C
加入S中(此时求出了源点A到C
的最短路径长度。 S={A,C}
(3)以C
为考虑的中间点,修改节点C的出边邻接点B
的最短路径长度,此时源点A到节点B的最短路径有两条,即一条经过节点C,一条不经过节点C。
修改源点A到顶点B的最短路径长度=min(不经过节点C的最短路径,经过节点C的最短路径)
以此方法求出各个节点到源点的最短路径:
第一次探索
s={A,C} |
U={B,D,E,F} |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
dist[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | min(A->B,A->C->B)=5 | 3 | 6 | 7 | ∞ |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
path[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 2 | 0 | 2 | 2 | -1 |
U集中dist 值 min(5,6,7,∞)=5 ,因此B加入到S集
第二次探索
s={A,B,C} |
U={D,E,F} |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
dist[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 5 | 3 | min(6,11)=6 | 7 | ∞ |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
path[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 2 | 0 | 2 | 2 | -1 |
U集中dist 值 min(6,7,∞)=6 ,因此D加入到S集
第三次探索
s={A,B,C,D} |
U={E,F} |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
dist[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 5 | 3 | 6 | min(7,8)=7 | 9 |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
path[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 2 | 0 | 2 | 2 | 3 |
U集中dist 值 min(7,9)=6 ,因此F加入到S集
第四次探索
s={A,B,C,D,F} |
U={E} |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
dist[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 5 | 3 | 6 | min(7,9+5)=7 | 9 |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
path[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 2 | 0 | 2 | 2 | 3 |
U集中dist 值 min(E)=7 ,因此E加入到S集
最终结果: 源点到达各点的最短路径为dist数组中的值
s={A,B,C,D,E,F}
u={}
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
dist[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 5 | 3 | 6 | 7 | 9 |
A | B | C | D | E | F | |
---|---|---|---|---|---|---|
path[]: | 0 | 1 | 2 | 3 | 4 | 5 |
0 | 2 | 0 | 2 | 2 | 3 |
三. java代码实现
GitHub源代码地址: https://github.com/yuanjiejiahui/Dijkstra
核心代码:
public void dijkstra(V v0, V vi) {
// 从顶点vO出发,查找到vi的最短路径
// listU 记录还未处理的节点
ArrayList<Integer> listU = new ArrayList<>();
// dist[] 记录各个节点到起始节点的最短权值
int[] dist = new int[this.vertices];
// 记录各个节点的上一级节点(用来联系该节点到起始节点的路径)
int[] path = new int[this.vertices];
int start = this.vertexList.indexOf(v0); // 源点序号
int end = this.vertexList.indexOf(vi); // 结束顶点序号
// 初始化U集合
for (int i = 0; i < this.vertices; i++) {
if (i == start) { // S={start}
continue;
}
listU.add(i); // u={vi}/{start}
}
// 初始化dist[],path[]
for (int i = 0; i < this.vertices; i++) {
// dist[]的当前节点权值就等于start->i节点的权值;初始化所有节点到源点的最短距离
dist[i] = this.edgeMatrix[start][i];
if (this.edgeMatrix[start][i] == Integer.MAX_VALUE) {
path[i] = -1; // 节点i不可达
} else {
path[i] = start; // 若start能直达某点,则表示节点i可以直接访问到start;
}
}
// 记录最小值的节点序号
int minIndex;
// int minIndexByI=0;
do {
System.out.println("集合U的状态: " + listU);
// dist数组下标
minIndex = listU.get(0);
for (int i = 1; i < listU.size(); i++) {
if (dist[listU.get(i)] < dist[minIndex]) {
minIndex = listU.get(i);
// minIndexByI = i;
}
}
listU.remove((Integer) minIndex);
// listU.remove(minIndexByI);
// 更新dist和path数组,主要考察minIndex节点纳入S,即新加入节点最短路径变化.
for (int i = 0; i < this.vertices; i++) {
if (this.edgeMatrix[minIndex][i] != 0 && this.edgeMatrix[minIndex][i] < Integer.MAX_VALUE) {
// 找到minIndex的所有邻接点
if (this.edgeMatrix[minIndex][i] + dist[minIndex] < dist[i]) {
// 新加入节点更短
dist[i] = this.edgeMatrix[minIndex][i] + dist[minIndex];
path[i] = minIndex;
}
}
}
} while (minIndex != end && !listU.isEmpty());
System.out.println("节点" + v0 + "=>" + vi + "最短路径是: " + dist[end]);
String str = "" + vi;
int i = end;
do {
i = path[i];
str = this.vertexList.get(i) + "=>" + str;
} while (i != start);
System.out.println(str);
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)