一、Dijkstra算法概述
        Dijkstra算法是一种经典的用于求解图中单源最短路径的算法,由荷兰计算机科学家Edsger W. Dijkstra在1959年提出。以下是对Dijkstra算法的详细概述:

1.1 基本概念
单源最短路径:从图中某一指定顶点(源点)出发,到图中其余各顶点的最短路径问题。

边权重:在带权图中,每条边都对应一个权重值,代表两顶点之间的距离或成本。

1.2 算法思想
        Dijkstra算法的基本思想是从源点开始,逐步确定到达其他各顶点的最短路径。在每一步中,它都选择当前已确定最短路径的顶点集合中,距离源点最近的顶点,并更新与该顶点相邻的顶点的最短路径估计值。

1.3 算法步骤
初始化:将所有顶点的最短路径估计值设置为无穷大(或一个很大的数),源点的最短路径估计值设为0。同时,创建一个优先队列(或使用其他数据结构)来存储待处理的顶点,并标记源点为已处理。

迭代处理:从优先队列中取出当前距离源点最近的顶点u(即估计值最小的顶点),将其标记为已处理。对于顶点u的每个邻接顶点v,如果通过顶点u到达顶点v的路径比当前已知的顶点v的最短路径更短,则更新顶点v的最短路径估计值,并将其加入优先队列(如果尚未加入)。

重复迭代:重复步骤2,直到优先队列为空或已找到目标顶点的最短路径。

1.4 算法特点
准确性:Dijkstra算法能够准确找到单源节点到其他所有节点的最短路径。

适用范围:适用于边权重非负的图,包括有向图和无向图。

效率:算法的时间复杂度取决于图的结构和实现的细节。在最坏情况下,时间复杂度为O(V^2)(V为顶点数),但通过使用优先队列等数据结构,可以将时间复杂度降低到O((V+E)logV)(E为边数)。

二、Dijkstra算法优缺点和改进
2.1  Dijkstra算法优点
准确性:Dijkstra算法能够准确找到单源节点到其他所有节点的最短路径,保证结果的最优性。

适用性广泛:该算法适用于各种图形结构,如道路网络、通信网络、计算机网络等,可用于求解这些领域中的最短路径问题。

易于理解和实现:Dijkstra算法的思想简单明了,易于学习和实现,常用于教学和实际应用中。

支持边权重非负的图:在边权重非负的图中,Dijkstra算法能够高效地进行最短路径计算。

支持自动路径恢复:通过记录每个节点的前驱节点信息,可以很容易地恢复出起始节点到目标节点的最短路径。

2.2  Dijkstra算法缺点
无法处理含负权边的图:由于Dijkstra算法基于贪心策略,当图中存在负权边时,可能导致算法无法正确计算出最短路径。

时间复杂度较高:在稀疏图中,Dijkstra算法的效率相对较低,因为需要对每个节点的邻居进行遍历,导致时间复杂度较高。

牺牲部分性能以保证准确性:作为一种确定性算法,Dijkstra算法在追求准确性的同时,可能会牺牲一定的性能,特别是在特别大规模的图中,其效率可能不如一些随机性算法。

2.3  Dijkstra算法改进
使用优先队列优化:传统的Dijkstra算法使用线性查找来找到当前未处理节点中距离最小的节点,这在大规模图中效率较低。通过使用优先队列(如最小堆)来存储节点及其距离,可以显著提高查找效率。

斐波那契堆优化:斐波那契堆是一种更高级的数据结构,它能够在O(1)平均时间内执行插入和删除最小元素的操作,进一步提高了Dijkstra算法的效率。

A*算法结合:对于需要快速找到特定节点到目标节点最短路径的场景,可以结合A算法。A算法在搜索过程中引入了启发式函数来评估节点的优先级,从而能够更快地找到目标节点。

并行计算:随着计算机硬件技术的发展,可以利用多线程或分布式计算等技术对Dijkstra算法进行并行化处理,以进一步提高算法的执行效率。

 

代码实例如下:


#include <stdio.h>
#include <limits.h>
 
#define V 9
 
// 用于找到最短路径集合中距离最小的顶点
int minDistance(int dist[], int sptSet[]) {
    int min = INT_MAX, min_index;
    for (int v = 0; v < V; v++) {
        if (sptSet[v] == 0 && dist[v] <= min) {
            min = dist[v];
            min_index = v;
        }
    }
    return min_index;
}
 
// 打印构建的距离数组
void printSolution(int dist[]) {
    printf("Vertex \t Distance from Source\n");
    for (int i = 0; i < V; i++)
        printf("%d \t\t %d\n", i, dist[i]);
}
 
// 使用Dijkstra算法计算从源顶点s到所有其他顶点的最短路径
void dijkstra(int graph[V][V], int s) {
    int dist[V]; // dist[i]将会保存从源s到i的最短路径的长度
    int sptSet[V]; // sptSet[i]为真如果顶点i包含在最短路径树中或最短距离从s到i是确定的
 
    // 初始化所有距离为无穷大,sptSet[]为false
    for (int i = 0; i < V; i++) {
        dist[i] = INT_MAX;
        sptSet[i] = 0;
    }
 
    // 源顶点到自身的距离始终是0
    dist[s] = 0;
 
    // 找到所有顶点的最短路径
    for (int count = 0; count < V - 1; count++) {
        int u = minDistance(dist, sptSet);
        sptSet[u] = 1;
 
        // 更新顶点u相邻顶点的距离值
        for (int v = 0; v < V; v++) {
            if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
            }
        }
    }
 
    // 打印构建的距离数组
    printSolution(dist);
}
 
// 测试代码
int main() {
    int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},
                       {4, 0, 8, 0, 0, 0, 0, 11, 0},
                       {0, 8, 0, 7, 0, 4, 0, 0, 2},
                       {0, 0, 7, 0, 9, 14, 0, 0, 0},
                       {0, 0, 0, 9, 0, 10, 0, 0, 0},
                       {0, 0, 4, 14, 10, 0, 2, 0, 0},
                       {0, 0, 0, 0, 0, 2, 0, 1, 6},
                       {8, 11, 0, 0, 0, 0, 1, 0, 7},
                       {0, 0, 2, 0, 0, 0, 6, 7, 0}};
 
    dijkstra(graph, 0);
    return 0;
}
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/xiaoyingxixi1989/article/details/142595349


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/xiaoyingxixi1989/article/details/142595349

Logo

集算法之大成!助力oier实现梦想!

更多推荐