浅谈【数据结构】图-最短路径问题

news2024/11/14 13:25:44

目录

1、最短路径问题

2、迪杰斯特拉算法

3、算法的步骤


谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注

没错,说的就是你,不用再怀疑!!!

希望我的文章内容能对你有帮助,一起努力吧!!!


1、最短路径问题

最短路径问题:是指在图中找到两个顶点,求两个顶点之间最短路径的一个问题。

“最短”:通常来说是指路径上面总权值最小,权值(边/弧的长度、成本、时间...)。

最短路径问题计算机科学、运筹学、网络理论等多个领域都有广泛的应用。

在图中,路径是指:一个顶点到另一个顶点的方式。一个顶点到另一个顶点方式并不一定是唯一的,在 多个路径中找一个总权值最小的一个路径。

解决带权的有向图两个顶点之间最短路径问题

两个经典算法:

  • 迪杰斯特拉算法(Dijkstra)
  • 弗洛伊德算法(Floyd)

2、迪杰斯特拉算法

Dijkstra算法:是解决从网络中任意一个顶点(源点)出发,求它到其他顶点(终点)的最短路径的问题。

算法思路:按路径长度递增次序产生从某个源点v到图中其余各项顶点的最短路径

Dijkstra算法依赖两个辅助向量:

  • 向量S[n]
    • S[i]==1 (true),说明从源点v到终点vi的最短路径已经找到了。
    • S[i]==0 (false) , 说明从源点v到终点vi的最短路径还没有找到。
    • 初始化开始S[v]==1 (true) , 其余各项顶点均为0 (false)。
  • 向量dist[n]
    • dist[n]存放从源点v到终点vi这个顶点当前的最短路径
    • 初始化
      • 当v可以直接到到vi的时候,那么dist[vi] = 的权值w
      • 当v不可以直接到到vi的时候,那么dist[vi] = 无穷大

3、算法的步骤

很显然从源点v到其它各项顶点的最短路径中的第一短的路径,绝对是能直接到到达的顶点(邻接点)中 最短的一条路径

  • 第一步:
    • 从源点v到其它各项顶点的当前最短路径找出最短的来。
      • dist[u] = min{dist[w] (w=0,1,2,3,4,5....n-1),并且S[w]==0 (false))}
        • 最优路径=当前已知的最短路径中最短的一条
      • dist[u] 称为当前最优路径,u为当前最优的顶点下标
  • 第二步:
    • 用当前最优路径来更新其他的路径
      • 对S[w] == 0 的w(没有找到最优路径的顶点)进行更新。
      • 如果dist[u]+ 小于 dist[w] , 那么就更新dist[w]
  • 第三步:
    • 重复第一步和第二步

***迪杰斯特拉算法代码示例***

#include <iostream>

// 顶点数量是10个
#define VertexMaxCount 10

// 无穷大
#define MAXNUMBER (65535)

// 图类型
typedef struct 
{
    // 关系集
    int R[VertexMaxCount][VertexMaxCount];

    // 顶点集
    std::string V[VertexMaxCount];

    // 顶点数量
    int vertex_count;
}Graph;


// 关系类型
typedef  struct 
{
    int index_s; // 关系开始顶点下标
    int index_e; // 关系结束顶点下标
    int r;  // 关系
}R;

/*
    @brief 为一个邻接矩阵图增加一个顶点
    @param graph  需要增加顶点的图指针
    @param vertex 需要增加的顶点
*/
void addVertex(Graph *graph,std::string vertex)
{
    // 判断图是否存在
    if(!graph)
        return;
    
    // 添加新顶点
    graph->V[graph->vertex_count] = vertex;

    // 更新顶点数量
    graph->vertex_count++;
}

int getIndex(Graph*graph,std::string vertex)
{
    if(!graph)
        return -1;

    for(int index=0;index < VertexMaxCount;index++)
        if(graph->V[index] == vertex)
            return index; // 返回顶点在图中的下标

    return -1; // 表示顶点不在图中
}

/*
    @brief 为一个邻接矩阵图增加关系
    @param graph 需要增加关系的图指针
    @param r 增加新关系
*/
void addR(Graph *graph,R r)
{
    // 判断图是否存在
    if(!graph)
        return;
    
    // 添加关系
    graph->R[r.index_s][r.index_e] = r.r;
}

Graph *creatGraph()
{
    // 申请了一个邻接矩阵的空间
    Graph * graph = new Graph;

    std::cout << "请依次输入顶点:";
    // 增加顶点
    while(1)
    {
        std::string vertex = "结束";
        std::cin >> vertex;
        if(vertex == "结束")
            break; 

        // 增加进入图
        addVertex(graph,vertex);
    }

    // 先初始化关系
    for(int row = 0;row < VertexMaxCount;row++)
    {
        for(int column = 0;column < VertexMaxCount;column++)
            if(row == column)
                graph->R[row][column] = 0;
            else
                graph->R[row][column] = MAXNUMBER;
    }
    std::cout << "请输入顶点之间的关系:" << std::endl;
    // 增加关系
    while(1)
    {
        std::string start_vertex = "结束";
        std::string end_vertex = "结束";
        int ralation = MAXNUMBER;

        std::cin >> start_vertex;
        std::cin >> end_vertex;
        std::cin >> ralation;

        if(start_vertex == "结束"||end_vertex == "结束"||ralation == MAXNUMBER)
            break;

        R r;
        r.index_s = getIndex(graph,start_vertex);
        r.index_e = getIndex(graph,end_vertex);
        r.r = ralation;

        // 判断结点下班是否有效
        if(r.index_s == -1||r.index_e == -1)
            continue;

        // 存入关系
        addR(graph,r);
    }

    return graph;
}

/*
    @brief 打印一个邻接矩阵图
    @param graph 需要打印的邻接矩阵图指针
*/
void printGraph(Graph *graph)
{
    if(!graph)
        return ;
    
    std::cout << "\t";
    // 打印顶点
    for(int count=0;count < VertexMaxCount;count++)
        std::cout << graph->V[count] << "\t";
    std::cout << std::endl;

    // 打印关系
    for(int row = 0;row < graph->vertex_count;row++)
    {
        
        std::cout << graph->V[row] << "\t";
        for(int column = 0;column < VertexMaxCount;column++)
        {
            // 存在关系
            std::cout << graph->R[row][column] << "\t";
        }
        std::cout << std::endl;
    }
}

/*
    逻辑思路:
        算法的步骤
        很显然从源点v到其它各项顶点的最短路径中的第一短的路径,绝对是能直接到到达的顶点(邻接点)中最短的一条路径
        - 第一步:
        - 从源点v到其它各项顶点的当前最短路径找出最短的来。
            - dist[u] = min{dist[w] (w=0,1,2,3,4,5....n-1),并且S[w]==0 (false))}
            - 最优路径=当前已知的最短路径中最短的一条
            - dist[u] 称为**当前最优路径**,u为当前最优的顶点下标
        - 第二步:
        - 用当前最优路径来更新其他的路径
            - 对S[w] == 0 的w(没有找到最优路径的顶点)进行更新。
            - 如果dist[u]+<u,w> 小于 dist[w] , 那么就更新dist[w]
        - 第三步:
        - 重复第一步和第二步

    @brief 通过迪杰斯特拉算法求最短路径
    @param graph 需要进行最短路径查找的图
    @param v_src 源点
*/


// 两个辅助向量
static bool  S[VertexMaxCount];
static int dist[VertexMaxCount];

void Dijkstra(Graph *graph,std::string v_src)
{
//------------------------迪杰斯特拉准备工作---------------------------
    // 初始化向量S
    for(int count = 0;count < graph->vertex_count;count++)
        S[count] = false; // 把所有顶点初始化的时候置为没有找到最短路径

    // 将v_src 到 v_src设置为找到了最短路径:自己到自己的最优路径找到了
    int v_src_pos = getIndex(graph,v_src);
    S[v_src_pos] = true;

    // 初始化dist向量
    for(int count = 0;count < graph->vertex_count;count++)
        dist[count] = graph->R[v_src_pos][count]; // 权值存储到dist里面

    // 结束之后:dist存储了源点到其他顶点的路径权值

//------------------------正式开始迪杰斯特拉---------------------------
    int min_pos; // 用来存储当前最短路径的下标
    int min_w;   // 用来存储当前最短路径的权值

    for(int count = 0;count < graph->vertex_count-1;count++)
    {
        // 初始化当前最短路径的下标和权值
        min_pos = 0;
        min_w = MAXNUMBER;

        // 第一步:从源点v到其他各项顶点的当前最短路径中找出最短的路径
        for(int min_road_pos = 0;min_road_pos < graph->vertex_count;min_road_pos++)
        {
            // 最优路径=当前已知的最短路径中最短的一条
            if(S[min_road_pos]==false&&dist[min_road_pos] < min_w)
            {
                min_pos = min_road_pos; // 保存小的那个下标
                min_w   = dist[min_road_pos]; // 保存它的权值
            }
        }
        // 当循环结束,你就能拿到当前最短路径中的第一短

        std::cout << "当前最短路径为:" << graph->V[v_src_pos] << "->" << graph->V[min_pos] << ":" << min_w << std::endl;

        // 这一条路径是源点到min_pos顶点的最优路径了,标记它
        S[min_pos] = true;

        // 第二步:通过这个最短路径来更新其他顶点路径
        for(int pos = 0;pos < graph->vertex_count;pos++)
        {
            //  如果dist[min_pos]+<min_pos,pos> 小于 dist[pos] , 那么就更新dist[pos]
            if(S[pos] == false&&dist[min_pos]+graph->R[min_pos][pos] < dist[pos])
            {
                // 更新pos对应的顶点的路径
                dist[pos] = dist[min_pos] + graph->R[min_pos][pos];
            }
        }
    }
    // 整个循环结束之后,从v_src到其他各项顶点的最短路径就求出来了

    for(int count = 0; count < graph->vertex_count;count ++)
    {
        std::cout << graph->V[v_src_pos] << "->" << graph->V[count] << ":" << dist[count] << std::endl;
    }
}


int main()
{
    Graph *g = creatGraph();

    printGraph(g);

    Dijkstra(g,"a");

    delete g;
    
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2080590.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

足球数据分析管理系统(JSP+java+springmvc+mysql+MyBatis)

项目文件图 项目介绍 随着足球运动的专业化和商业化程度不断提高&#xff0c;对运动员的表现进行分析和管理变得越来越重要。一个高效的足球运动员数据管理系统可以帮助教练团队、球探和俱乐部管理层全面了解每位运动员的训练情况、比赛表现、身体状态和其他关键指标。这样的系…

Leetcode JAVA刷刷站(99)恢复二叉搜索树

一、题目概述 二、思路方向 要解决这个问题&#xff0c;我们可以采用中序遍历二叉搜索树&#xff08;BST&#xff09;的方法&#xff0c;因为中序遍历BST会返回一个有序的数组。由于只有两个节点被错误地交换了&#xff0c;所以中序遍历的结果中将有两个位置上的元素是逆序的。…

AD7606芯片驱动-FPGA实现

简介 AD7606是一款16位ADC芯片&#xff0c;可实现8通道并行采集&#xff0c;每通道最大速度可达1M&#xff0c;可实现多种模式数据采集。 介绍 本次FPGA使用的是8通道串行采样模式&#xff0c;设计中所用到的AD7606引脚说明如下&#xff1a; 名称定义CONVST同步采集转换开始信…

并发服务器开发基础

一、服务器模型 1. 单循环服务器&#xff1a; 单循环服务器在同一时刻只能处理一个客户端的请求。由于其结构简单&#xff0c;适合低负载的场景&#xff0c;但在并发请求增加时可能导致性能问题。 2. 并发服务器模型&#xff1a; 并发服务器可以同时响应多个客户端…

openzgy编译和测试应用

zgy是仅次于segy重要的地震数据格式,最早在petrel软件中使用,目前已基本成为行业标准,具有更快的数据存储效率。openzgy是其开源版本。 ZGY文件格式由Schlumberger公司开发,用于存储地震解释的三维数据。OpenZGY库提供了读写该格式的能力。存在C++和Python两种版本。对于P…

web应用程序之服务器部署

当一个web应用层序开发好后&#xff0c;无论你是用什么语言&#xff0c;最后都要考虑部署到服务器上测试使用&#xff0c;这里就常见的服务器上部署进行如下的摸索总结。WSGI&#xff08;Web Server Gateway Interface&#xff09;&#xff0c;翻译为Python web服务器网关接口&…

【与C++的邂逅】--- 模板初阶

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 与C的邂逅 本篇博客我们将了解C中泛型编程体现的一大利器 --- 模板&#xff0c;有了模板可以帮我们用户省力。 &#x1f3e0; 泛型编程 如何实现一个通…

二叉树的三个简单题

1、二叉树的第k个结点 思路解析 由题可知这是一棵二叉搜索树 它或者是一棵空树&#xff0c;或者是具有下列性质的二叉树&#xff1a; 1. 若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值&#xff1b; 2. 若它的右子树不空&#xff0c;则右子树…

LSTM唐诗生成

LSTM唐诗生成 1课程简介1-2递归神经网络RNN1-3RNN网络细节1-4LSTM网络架构2-1处理Minist数据集2-2RNN网络模型及训练3-1任务概述与环境配置3-2参数配置3-3数据预处理模块3-4batch数据制作3-5RNN模型定义3-8测试唐诗生成效果 1课程简介 使用深度网络模型 写首歌 写个剧本等 原…

openshift node NotReady kubelet http: TLS handshake error

文章目录 问题现象解决方法 问题现象 openshift 集群 node 节点 notready $ oc get node NAME STATUS ROLES AGE VERSION master1.ocp4.demo.com Ready control-plane,master 4d14h v1.29.76abe8a1 master2.ocp4…

折腾 Quickwit,Rust 编写的分布式搜索引擎-官方教程

快速上手 在本快速入门指南中&#xff0c;我们将安装 Quickwit&#xff0c;创建一个索引&#xff0c;添加文档&#xff0c;最后执行搜索查询。本指南中使用的所有 Quickwit 命令都在 CLI 参考文档 中进行了记录。 https://quickwit.io/docs/main-branch/reference/cli 使用 Qui…

光庭信息半年报:营收利润「双」下降,汽车软件业务竞争加剧

「软件定义汽车」概念&#xff0c;不可否认强化了软件在整车价值的权重、带动更多供应商争夺软件业务的同时&#xff0c;也同样埋下了不小的风险。 比如&#xff0c;在汽车行业&#xff0c;常见的软件业务有两种&#xff1a;1、软件许可/IP&#xff0c;这类产品服务主要集中于…

MacOS 本地打开android模拟器

MacOS 本地打开android模拟器 查看本地安卓模拟器&#xff1a;emulator -list-avds 注意&#x1f4e2;&#xff1a;这里会提示你找不到 emulator 命令&#xff0c;此时我们需要进入 cd ~/Library/Android/sdk/tools/ 查看模拟器列表&#xff1a;./emulator -list-avds 启动…

PHP概述-特点-应用领域-如何学习

老师建议注册使用百度文心一言&#xff1b;讯飞星火大模型-AI大语言模型-星火大模型-科大讯飞&#xff1b;Kimi.ai - 帮你看更大的世界 等人工智能工具软件的一个到两个&#xff0c;也可下载文心一言、讯飞星火、kimi等APP软件使用&#xff0c;对于我们在读的大二学生来说有什么…

需方软件供应链安全保障要求及开源场景对照自评表(上)

国标《信息安全技术 软件供应链安全要求》确立了软件供应链安全目标&#xff0c;规定了软件供应链安全风险管理要求和供需双方的组织管理和供应活动管理安全要求。 开源软件供应链作为软件供应链的一种特殊形式&#xff0c;该国标亦适用于指导开源软件供应链中的供需双方开展组…

BaseCTF [Week2] 最简单的编码

前言&#xff1a;做题笔记。 下载解压 查壳。 64ida打开。 查找字符串。 跟进。 逆着向前看。 说明是密文。 里面是base64的变异加密。 原base64关键加密&#xff1a; &#xff08;看BaseCTF week1 [第一周]BasePlus 官方WP&#xff09; 变种后&#xff1a; 在此基础上加上了…

安卓系统 XBL阶段详解

在安卓系统的启动流程中&#xff0c;XBL&#xff08;eXtensible Boot Loader 或 Secondary Bootloader&#xff09;是一个关键阶段&#xff0c;特别是在使用QualComm&#xff08;高通&#xff09;等SOC&#xff08;System on Chip&#xff09;的设备上。以下是对XBL阶段的详细解…

Yololov5+Pyqt5+Opencv 实时城市积水报警系统

在现代城市生活中&#xff0c;积水问题不仅影响交通和人们的日常生活&#xff0c;还可能对城市基础设施造成潜在的威胁。为了快速、准确地识别和应对积水问题&#xff0c;使用计算机视觉技术进行智能积水检测成为一个重要的解决方案。在这篇博客中&#xff0c;我将带你一步步实…

数据结构(邓俊辉)学习笔记】串 08——KMP算法:再改进

文章目录 1. 美中不足2. 以卵击石3. 前车之覆4. 后车之鉴5. 可视对比 1. 美中不足 以上&#xff0c;我们不仅给出了 KMP 算法&#xff0c;同时也证明它的时间复杂度已经达到了渐进意义上的最优&#xff0c;也就是最坏情况也不超过 O(n)。而该算法目前这个版本也绝非完美无缺&am…

005、架构_数据节点

​DN组件总览 ​ DN节点包含进程 dbagent进程:主要提供数据节点高可用、数据导入导出、数据备份恢复、事务一致性、运维类功能、集群的扩缩容、卸数等功能;MySQL进程:主要提供数据一致性、分组管理、快同步复制、高低水位等;