最短路径之基于贪心算法的迪杰斯特拉dijkstra算法(有图解,含码源)

简介: 最短路径之基于贪心算法的迪杰斯特拉dijkstra算法(有图解,含码源)

目录


迪杰斯特拉算法介绍

算法知识点

算法思路

算法前的准备

算法步骤

模板代码

例题带图解析


正文


迪杰斯特拉算法介绍


迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。


迪杰斯特拉算法用于查找图中某个顶点到其它所有顶点的最短路径,该算法既适用于无向加权图,也适用于有向加权图。

注意,使用迪杰斯特拉算法查找最短路径时,必须保证图中所有边的权值为非负数,否则查找过程很容易出错。


算法知识点


贪心算法是一种对某些求最优解问题的更简单、更迅速的设计技术。贪心算法的特点是一步一步地进行,常以当前情况为基础根据某个优化测度作最优选择,而不考虑各种可能的整体情况,省去了为找最优解要穷尽所有可能而必须耗费的大量时间。贪心算法采用自顶向下,以迭代的方法做出相继的贪心选择,每做一次贪心选择,就将所求问题简化为一个规模更小的子问题,通过每一步贪心选择,可得到问题的一个最优解。虽然每一步上都要保证能获得局部最优解,但由此产生的全局解有时不一定是最优的,所以贪心算法不要回溯


算法思路


通过Dijkstra计算图G中的最短路径时,需要指定一个起点D(即从顶点D开始计算)。

此外,引进两个数组S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点D的距离)。

初始时,数组S中只有起点D;数组U中是除起点D之外的顶点,并且数组U中记录各顶点到起点D的距离。如果顶点与起点D不相邻,距离为无穷大。

然后,从数组U中找出路径最短的顶点K,并将其加入到数组S中;同时,从数组U中移除顶点K。接着,更新数组U中的各顶点到起点D的距离。

重复第4步操作,直到遍历完所有顶点。


算法前的准备


需要借助三个辅助向量(数组):

       v:表示以v为下标的起点

   1.数组 s[n] 标记这个最短路径有没有被求出

       s[i] = 1; 当源点v到vi的最短路径求出

       s[i] = 0; 源点v到vi的最短路径没有被求出

     

           s[0]: 表示v->v0的最短路径有没有被求出

           s[1]: 表示v->v1的最短路径有没有被求出

           s[2]: 表示v->v2的最短路径有没有被求出

           ....

           s[i]: 表示v->vi的最短路径有没有被求出

                初始时,s[v] = 1,其它的s[i] = 0

   2.数组dist[n]  最短路径距离

 

       dist[i] 源点v到vi的最短路径长度

           初始时:

               dist[i] = <v,vi> = w;

               <v,vi>的权w,若p(v,vi)存在,表示v到vi有一条直接路径

               dist[i] = VERY_BIG ,p(v,vi)不存在,表示v到vi没有一条直接路径

             

   3.path[n]

       源点v到vi的最短路径  (v,...vi)

           初始时,path[i] = {v}


算法步骤


假设图中有n个顶点,Dijkstra是要求n-1条最短路径,即源点v到其它n-1个顶点的边(最短路径)

       step1:

           源点v到其它各个顶点的第一条最短路径长度 dis[u] = MIN{dist[w]| w= 0,1,2..n-1且s[w] = 0}

           表示:

               在所有没有被找到最短路径中找到一条最短的,这条路径当做当前求出的最短路径长度。

             

               eq: dist[B] = Min{dis[B], dist[C],dist[D]}

                   假设dist[B]为最短路径

                       即A-B (源点A)的最短路径为dist[B] 且 s[B] = 1;

                           证明:

                               A->B

                               用穷举法:

                                   A->B : dist[B]

                                   A->C->B :dist[c] + x  > dist[B]

                                   所以得证。

                                   dist[u]最为当前最短路径 s[u] = 1:表示v->u的最短路径已经被求出。

     

       step2:

           对所有s[w] = 0(其它所有未被求出的最短路径的点),更新dist[w]

               if dist[u] + <u , w> < dist[w] //说明我有一条更短的路径到w

                   dist[w] = dist[u] + <u , w> //即更新dist[w]

                 

                   把step1 step2 重复n-1次 就可以求出最短距离


模板代码


int s[MAXN];//是否已经求出最短路径的标志数组 s[i]==1 :表示v到vi最短路径已经求出 ; s[i] == 0:表示v到vi最短路径没有求出
int dist[MAXN];//存放当前源点到各顶点的最短路径长度
int path[MAXN];//存放的源点到终点i的最短路径是利用哪个最优点更新的 
//用迪杰斯特拉算法求出v点到其它各顶点的最短路径
void Dijkstra(Graph *g, int v)
{
    //step 1 初始化辅助数组
    int i;
    for( i = 0; i < g->vexnum; i++)
    {
        s[i] = 0;//一开始都为0
        dist[i] = g->Adj[v][i];//邻接矩阵权值
        path[i] = v;//每条最短路径起点都为v
    }
    s[v] = 1;
    dist[v] = 0;
    //step2 在所有没有被求出来的最短路径找出一条最短的 长度当成当前求出的最短路径
    int min;//求最优顶点的记录板
    int i_min;//最优顶点下标
    int times; //寻找最短路径的次数  每次只找一条n-1
    for(times = 0; times < g->vexnum-1; times++)
    {
        //step1 求出当前最优顶点
        min = VERY_BIG;
        for(i = 0; i < g->vexnum; i++)
        {
            if(s[i] == 0 && dist[i] < min)
            {
                min = dist[i];
                i_min = i;
            }
        }
        s[i_min] = 1;//最短路径已经求出
        //step2 根据最优顶点更新其它dist
        for(i = 0; i < g->vexnum; i++)
        {
            if(s[i] == 0)
            {
                if(dist[i_min] + g->Adj[i_min][i]  < dist[i])
                {
                    dist[i] = dist[i_min] + g->Adj[i_min][i];
                    path[i] = i_min;
                }
            }
        }
    }
}
// a -> b: 15 输出所有最短路径值
void print_dist(Graph *g, int v)
{
    int i;
    for(i = 0; i < g->vexnum; i++)
    {
        printf("the %c -> %c : %d\n",g->V[v], g->V[i], dist[i]);
    }
}
void print_path(Graph *g, int v)
{
    int i;
    for(i = 0; i < g->vexnum; i++)
    {
        if(dist[i] == VERY_BIG)
        {
            printf("%c -> %c is no path\n",g->V[v], g->V[i]);
            continue;
        }
    }
    printf("%c ->%c : %c",g->V[v], g->V[i],g->V[i]);
    int pre_index = path[i];
    while(1)
    {
        printf("%c ",g->V[pre_index]);
        if(pre_index == v)//已经回到了出发点
        {
            break;
        }
        pre_index = path[pre_index];
    }
    printf("\n");
}


例题带图解析


例题来源,自创,是笔者经过计算后,包含了大部分情况。                                                    (求A点到各点的最短路径)

0000000000000000000000000000000000000000000000000000000000.jpeg

名称解释:


       标志:为1 时表示已找到最短路径,为0 时表示还未找到最短路径


       距离:目前从A点到目的点的最短距离


       路径:目前从A点到目的点的最短路径


       --:目前无法到达


这是第一轮寻路,以A为起点。


A
B C D E F G
标志 1 0 0 0 0 0 0
距离 0 3 2 -- -- -- --
路径 A A->B A->c -- -- -- --

上述距离最短的是A->C为2,因此C的最短路径找到了,C的标志为变为1,下一轮以A->C这条路径为起点,继续寻路

第二轮寻路,以A->C为起点,图中可以看出,C继续往下走,可以到D点与F点。




A
B C D E F G
标志 1 0 1 0 0 0 0
距离 0 3 2 10 -- 6 --
路径 A A->B A->C A->C->D -- A->C->D --

比较距离时,比较的是标志位为0的有数距离,第二轮就算比较B,D,F三点距离,这里可以看到A->B距离最小,因此到B点的最小路径找到,为A->C,距离为2。下一轮以A->C这条路径为起点,继续寻路。


后面的与这两步都一样,这里就不赘述啦,就留一点给小伙伴们发挥的空间,也可以将自己后续的寻路步骤发到评论区大家一起讨论哦。互通有无,互相进步。

相关文章
|
1月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
69 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
8天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
25 2
|
1月前
|
算法 Java C++
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
【贪心算法】算法训练 ALGO-1003 礼物(C/C++)
|
1月前
|
存储 算法 程序员
迪杰斯特拉(Dijkstra)算法(C/C++)
迪杰斯特拉(Dijkstra)算法(C/C++)
|
2月前
|
算法 前端开发
一文了解贪心算法和回溯算法在前端中的应用
该文章深入讲解了贪心算法与回溯算法的原理及其在前端开发中的具体应用,并通过分析LeetCode题目来展示这两种算法的解题思路与实现方法。
|
3月前
|
机器学习/深度学习 算法 Java
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
这篇文章介绍了基于贪婪技术思想的Prim算法和Dijkstra算法,包括它们的伪代码描述、Java源代码实现、时间效率分析,并展示了算法的测试用例结果,使读者对贪婪技术及其应用有了更深入的理解。
算法设计(动态规划应用实验报告)实现基于贪婪技术思想的Prim算法、Dijkstra算法
|
24天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
9天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。
|
10天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。
|
11天前
|
存储 算法 决策智能
基于免疫算法的TSP问题求解matlab仿真
旅行商问题(TSP)是一个经典的组合优化问题,目标是寻找经过每个城市恰好一次并返回起点的最短回路。本文介绍了一种基于免疫算法(IA)的解决方案,该算法模拟生物免疫系统的运作机制,通过克隆选择、变异和免疫记忆等步骤,有效解决了TSP问题。程序使用MATLAB 2022a版本运行,展示了良好的优化效果。