Dijkstra算法
迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
特点:
1、Dijkstra算法是求图中单源路径最短的算法,即是求图内一个起始点开始到其他某一终点结束的最短路径算法。
2、该算法的路径权值必须全为正数,若路径权值存在负数则需要使用Bellman-Ford算法;若求图内任意两点之间的最短路径,则需要使用Floyd算法。
3、Dijkstra算法适用稠密图(邻接矩阵),因为稠密图问题与顶点关系密切;
4、Bellman-Ford算法适用稀疏图(邻接表),因为稀疏图问题与边关系密切;
5、Floyd算法在稠密图(邻接矩阵)和稀疏图(邻接表)中都可以使用。
算法基本策略
1.每次从未标记的节点中选择距离出发点最近的节点,标记,收录到最优路 径集合中。
2.计算刚加入节点A的邻近节点B的距离(不包含标记的节点)。若(节点A的距离+节点A到节点B的边长)<节点B的距离,就更新节点B的 距离和前面点。
(参考B站视频最短路径查找—Dijkstra算法)
尝试代码实现(个人版)
以上述视频中的无向连通图为例,使用Java语言以上述策略为基础手写代码实现查找从定点0到顶点4的最短路径以及最短路径长度。
//应得到PreNode[] = {-1,0,1,2,5,6,7,0,2}
//应得到Path[] = {0,4,12,19,21,11,9,8,14}
public class Dijkstra {
//使用邻接矩阵对示例图进行存储
int vertex[] = {0,1,2,3,4,5,6,7,8};
//将无直接相连两点的路径设置为inf
int inf = Integer.MAX_VALUE;
int Matrix[][] = {
{inf,4,inf,inf,inf,inf,inf,8,inf},
{4,inf,8,inf,inf,inf,inf,11,inf},
{inf,8,inf,7,inf,4,inf,inf,2},
{inf,inf,7,inf,9,14,inf,inf,inf},
{inf,inf,inf,9,inf,10,inf,inf,inf},
{inf,inf,4,14,10,inf,2,inf,inf},
{inf,inf,inf,inf,inf,2,inf,1,6},
{8,11,inf,inf,inf,inf,1,inf,7},
{inf,inf,2,inf,inf,inf,6,7,inf}
};
//设置Path数组存储起点0到各点的最短距离,将起点值设为Path中最小值
int Path[] = {0,inf,inf,inf,inf,inf,inf,inf,inf};
//设置PreNode数组存储在0到该点最短路径的上一个连接本顶点的点
int PreNode[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
//设置Visit数组用于记录各顶点是否被扫描
boolean Visit[] = {false,false,false,false,false,false,false,false,false};
public void DijkstraSearch(int [][]matrix) {
while (true) {
//扫描Path数组寻找路径长度最小值,并使用index记录最小长度下标
int mini = inf;
int index = -1;
for (int i = 0; i < Path.length; i++) {
if (Visit[i] == false) {
if (Path[i] < mini) {
mini = Path[i];
index = i;
}
}
}
//当index值为-1时,说明Visit数组中的值全部为true,遍历结束
if(index == -1){break;}
//将所找到的顶点Visit[]数组中的对应值改写为True
Visit[index] = true;
//查找邻接矩阵中与该顶点直接相邻的顶点路径,并对应更新Path数组
for (int j = 0; j < vertex.length; j++) {
//若在该点最短路径基础上加上其某一直接相邻点的路径值仍小于其目前最小路径
//则更新其最小路径(Path数组值)与上一顶点值(PreNode)
/*if (Matrix[index][j] + Path[index] < Path[j]) {
Path[j] = Matrix[index][j] + Path[index];
PreNode[j] = index;
}*/
//判断该新顶点作为中转顶点是否比之前存储的路径长度短
//判断Vertex[j]是否已被访问过
if((Matrix[index][j] != inf) && (Matrix[index][j] + Path[index] < Path[j])&&Visit[j] == false){
//更新Path数组和PreNode数组
Path[j] = Matrix[index][j] + Path[index];
PreNode[j] = index;
}
}
}
}
}
经测试,结果输出正确,与预期结果一致,算法实际遍历了图中的所有顶点,即时间复杂度为O(|V²|)(|V|为图中顶点数)。