最短路径(Dijkstra)算法

本文介绍Dijkstra算法的基本原理,详细阐述了如何通过该算法找出有向图中从单源点到其他各顶点的最短路径。算法首先将顶点分为已知最短路径和未知最短路径两组,然后逐步迭代更新顶点的距离,直至所有顶点的最短路径都被计算出来。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、算法功能:

给定一个出发点(单源点)和一个有向网G=(V, E), 求出源点到其它各顶点之间的最短路径。


二、算法思想:

(1)把图中顶点集合分成两组,第一组为集合S,存放已求出其最短路径的顶点,第二组为尚未确定最短路径的顶点集合是V-S(令W=V-S),其中V为网中所有顶点集合。

(2)按最短路径长度递增的顺序逐个把W中的顶点加到S中,直到S中包含全部顶点,而W为空。

(3)在加入的过程中,总保持从源点v到S中各顶点的最短路径长度不大于从源点v到W中任何顶点的最短路径长度。

(4)此外,每个顶点对应一个距离,S中的顶点的距离就是从v到此顶点的最短路径长度,W中的顶点的距离从v到此顶点只包括S中的顶点为中间顶点的当前最短路径长度。


三、实现步骤:

(1)初始时,S只包含源点,S={v},v的距离为0。U包含除v外的其他顶点,U中顶点的距离为顶点的权或∞ 。

(2)从U中选取一个距离最小的顶点k,把k加入到S中。

(3)以k 作为新考虑的中间点,**修改**U中各顶点的距离。

(4)重复步骤(1)、(2)直到所有顶点都包含在S中。


四、举例:

求v0到其它各点的最短路径:

Dijkstra题目

Dijkstra答案

答:最短路径为(V0,V2,V4,V3,V5)


五、算法实现:

/*======================================================
*   Copyright (C) 2017
*   
*   文件名称:dijkstra.c
*   创 建 者:ZhouYang
*   创建日期:2017年06月01日
*   描    述:dijkstra算法实现
*
====================================================*/

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define MAX_INT 32767

int main(void)
{
    int i,j,k;
    int vertexLen, edgeLen;
    int len_S,len_U;
    int min,weight,sum=0;
    char initial_node,final_node;
    char node,mid;
    char startVertex, endVertex;

    printf("please input vertex's number:");
    scanf("%d",&vertexLen);
    printf("please input edge's number:");
    scanf("%d",&edgeLen);

    int graph[vertexLen][vertexLen];
    char route[vertexLen];
    char S[vertexLen],U[vertexLen];
    int node_min[vertexLen];

    for(i=0;i<vertexLen;i++)
        for(j=0;j<vertexLen;j++){
            if(i==j)
                graph[i][j] = 0;
            else
                graph[i][j] = MAX_INT;
        }

    for(i=0; i<edgeLen; i++){
        printf("please input the %d edge's start vertex name (vertex name from a to %c):",i+1,'a'+vertexLen-1);
        scanf(" %c",&startVertex);
        printf("please input the %d edge's end vertex name (vertex name from a to %c):",i+1,'a'+vertexLen-1);
        scanf(" %c",&endVertex);
        printf("please input this edge's weight:");
        scanf("%d",&weight);

        graph[startVertex-'a'][endVertex-'a'] = weight; 
    }

    for(i=0;i<vertexLen;i++)
        node_min[i]=MAX_INT;

    printf("Input initial node:");
    scanf(" %c",&initial_node);
    printf("Input final node:");
    scanf(" %c",&final_node);

    S[0]=initial_node;
    j=0;
    for(i=0;i<vertexLen;i++)
    {
        if(initial_node != 'a'+i)
            U[j++]='a'+i;
    }
    len_S=1;
    len_U=4;

    node_min[initial_node-'a']=0;
    node=initial_node;

    for(i=0;i<vertexLen-1;i++)
    {
        for(j=0;j<vertexLen;j++)
        {
            if(node_min[j]>graph[node-'a'][j]+node_min[node-'a'])
            {
                node_min[j]=graph[node-'a'][j]+node_min[node-'a'];
            }
        }

        min=MAX_INT;
        for(j=0;j<len_U;j++)
        {
            if(min>node_min[U[j]-'a'])
            {
                min=node_min[U[j]-'a'];
                mid=U[j];
                k=j;
            }
        }
        while(k<len_U)
        {
            U[k]=U[k+1];
            k++;
        }
        len_U--;
        len_S++;
        S[len_S-1]=mid;
        node=mid;
    }

    mid=final_node;
    k=0;
    route[k++]=mid;
    while(1)
    {   
        for(i=0;i<vertexLen;i++)
        {
            if(mid!='a'+i)
            {
                if(node_min[mid-'a']-node_min[i]==graph[i][mid-'a'])
                {
                    sum += node_min[mid-'a']-node_min[i];
                    mid='a'+i;
                    route[k++]=mid;
                    break;
                }
            }
        }
        if(mid == initial_node)
            break;
    }

    for(i = k-1;i>0;i--)
        printf("%c-->",route[i]);
    printf("%c",final_node);
    printf("\nweight sum is %d",sum);
    return 0;
}

图如下:

这里写图片描述

运行结果:
这里写图片描述

### 迪杰斯特拉算法在有向图中的流程解析 迪杰斯特拉Dijkstra算法是一种用于解决单源最短路径问题的经典算法,在处理加权有向图时尤为有效。以下是基于参考资料的内容以及具体实现细节,对迪杰斯特拉算法在有向图中的应用进行详细说明。 #### 1. 初始状态设定 假设存在一个带有权重的有向图 \( G(V, E) \),其中 \( V \) 表示顶点集合,\( E \) 表示边集合。定义起点为 \( S \),目标是找到从 \( S \) 出发到达其他所有顶点的最短路径距离[^1]。 初始状态下: - 设置两个集合:`open` 和 `closed`。 - 将起点 \( S \) 放入 `open` 集合中,并将其当前的距离设为 0;其余顶点的距离暂时标记为无穷大 (\( ∞ \))。 #### 2. 算法核心逻辑 通过不断更新顶点之间的距离,逐步扩展已知区域直至覆盖全图: 1. **选取最小距离节点**:从未访问过的节点集合 (`open`) 中选出具有最小临时距离值的一个节点 \( u \)[^3]。 2. **松弛操作**:对于选定节点 \( u \) 的每一个邻居节点 \( v \),尝试更新它们的距离值。如果经过 \( u \) 能够让 \( v \) 的距离变得更小,则更新 \( v \) 的距离值并记录前驱节点为 \( u \)[^1]。 更新公式如下所示: ```python if distance[u] + weight(u, v) < distance[v]: distance[v] = distance[u] + weight(u, v) predecessor[v] = u ``` 3. **移动至闭合列表**:完成上述步骤后,将节点 \( u \) 移动到 `closed` 集合中表示已完成对其探索。 重复以上过程直到所有的节点都被加入到 `closed` 集合或者找不到更近的目标为止。 #### 3. 实际案例分析 考虑下述简单例子展示 Dijkstra 算法执行全过程: | Step | Open List | Closed List | Current Node | Distances | |------|------------------|----------------|--------------|--------------------| | Init | A | | | A=0, B=∞, C=∞... | | 1 | B,C,D | A | A | B=10, C=3,... | | ... | ... | ... | ... | ... | 最终得到的结果将是每个节点相对于起点的实际最短路径长度及其对应的前驱链表以便回溯完整路线[^2]。 --- ### 示例代码实现 下面给出 Python 版本的 Dijkstra 算法实现供参考: ```python import heapq def dijkstra(graph, start): distances = {node: float('infinity') for node in graph} distances[start] = 0 priority_queue = [(0, start)] while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) # 如果当前节点已经被处理过了则跳过 if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight # 只有当发现新的较短路径才更新 if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(priority_queue, (distance, neighbor)) return distances # 定义样例图结构 example_graph = { 'A': {'B': 1, 'C': 3}, 'B': {'A': 1, 'D': 2}, 'C': {'A': 3, 'D': 4}, 'D': {} } print(dijkstra(example_graph, 'A')) ``` 此段程序利用堆优化版优先队列加速寻找下一个最近未访问结点的过程从而提高效率[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值