【图】:常用图搜索(图遍历)算法

news2024/11/27 17:25:39

目录

  • 概念
  • 图遍历
    • 深度优先搜索 (DFS)
      • DFS 适用场景
      • DFS 优缺点
    • 广度优先搜索 (BFS)
      • BFS 适用场景
      • BFS 优缺点
    • DFS & BFS 异同点
  • 图搜索
    • Dijkstra算法
    • A*算法
    • Floyd算法
    • Bellman-Ford算法
    • SPFA算法

概念

图遍历和图搜索是解决图论问题时常用的两种基本操作。

  • 图遍历是指从图中的某一个节点出发,访问图中所有的节点,确保每个节点都被访问到且不会重复访问。图遍历有两种主要方式:深度优先搜索(DFS)广度优先搜索(BFS)
  • 图搜索是指在图中寻找特定目标的过程。搜索可能是无目标的(即只是为了遍历整个图),也可能是有目标的,希望找到特定的节点或路径。最常用的有目标图搜索算法是Dijkstra算法(用于找到单源最短路径)和A*算法(结合了BFS和启发式搜索,用于找到最优路径)。

图遍历

深度优先搜索 (DFS)

深度优先搜索(Depth First Search,DFS)是一种用于遍历或搜索树或图的算法。它从起始顶点开始,沿着一条路径直到不能继续为止,然后返回到最近的一个未访问过的节点,继续相同的过程,直到所有节点都被访问过。

在这里插入图片描述

function DFS(node):
    if node is not visited:
        mark node as visited
        for each neighbor of node:
            DFS(neighbor)

DFS 适用场景

  • 寻找路径:DFS 在寻找路径方面非常强大,可以用于解决迷宫问题、寻找图中两个节点之间的路径等。
  • 拓扑排序:DFS 可以用于在有向图中进行拓扑排序,例如在编译器优化、任务调度等领域中应用广泛。
  • 检测环路:DFS 可以用于检测图中是否存在环路,对于拓扑排序来说,有向无环图 (DAG) 才有拓扑排序的结果。
  • 生成最小生成树:DFS 可以用于生成最小生成树,例如在 Prim 算法中。

DFS 优缺点

优点:

  1. 节省空间:相比较于 BFS,DFS 使用递归实现时,不需要额外的数据结构来保存访问状态,因此可能会更节省空间。
  2. 发现深层次的节点:DFS 会尽可能深地探索某一条分支,因此在找到目标节点或解之前,会一直沿着一条路径向下探索。

缺点:

  1. 可能陷入死循环:如果图中包含循环,且没有合适的终止条件,DFS 可能会陷入无限循环。可能

  2. 找到的不是最短路径:由于 DFS 是尽可能深地探索某一条分支,所以找到的路径不一定是最短路径。


广度优先搜索 (BFS)

广度优先搜索(Breadth First Search,BFS)也是一种用于遍历或搜索树或图的算法。它从起始顶点开始,首先访问所有与起始顶点相邻的节点,然后逐层向下访问。

在这里插入图片描述

function BFS(start):
    create a queue Q
    enqueue start into Q
    mark start as visited

    while Q is not empty:
        current = dequeue from Q
        for each neighbor of current:
            if neighbor is not visited:
                mark neighbor as visited
                enqueue neighbor into Q

BFS 适用场景

  • 寻找最短路径:BFS 可以用于寻找图中两个节点之间的最短路径,因为它会逐层扩展,所以找到的路径一定是最短的。
  • 最小生成树 (Prim 算法):BFS 也可以用于 Prim 算法中生成最小生成树的过程。

BFS 优缺点

优势:

  1. 找到最短路径:BFS 适用于需要找到最短路径的情况,因为它会优先访问距离起点更近的节点。
  2. 避免陷入死循环:BFS 通常不容易陷入死循环,因为它会逐层扩展,不会无限制地向下探索。

缺点:

  1. 可能占用更多内存:BFS 通常需要一个队列来保存待访问节点,可能会占用比DFS更多的内存。
  2. 不一定能找到最深层次的节点:BFS 在发现目标节点时,不一定会沿着一条深度较大的路径找到它。

DFS & BFS 异同点

相同点:

DFS 和 BFS 都是图遍历算法,用于访问图中的所有节点,确保每个节点都被访问到。

不同点:

  1. 搜索方式:
    - DFS:尽可能深地探索某一条分支,直到不能继续为止,然后回溯。
    - BFS:先访问与起始节点直接相邻的所有节点,然后逐层向下访问。

  2. 适用场景:
    - DFS 适用于寻找路径、拓扑排序、检测环路等问题。
    - BFS 适用于寻找最短路径、最小生成树等问题。

  3. 找到的路径:
    - DFS 找到的路径不一定是最短路径。
    - BFS 一定能找到最短路径。

  4. 空间复杂度:
    - DFS 可能会节省一些空间,特别是使用递归实现时。
    - BFS 通常会占用更多的内存,因为需要一个队列来保存待访问节点。

总的来说,选择使用DFS还是BFS取决于具体的问题和需求。如果需要寻找最短路径或最优解,通常选择BFS。如果问题需要深度搜索或者对内存消耗有限制,可能会选择DFS


图搜索

图搜索根据目标可以分为,目标节点搜索目标路径搜索。

Dijkstra算法

给定一个带权有向图 G=(V,E) ,其中每条边的权是一个非负实数。另外,还给定 V 中的一个顶点,称为源。现在我们要计算从源到所有其他各顶点的最短路径长度。这里的长度是指路上各边权之和。这个问题通常称为单源最短路径问题,如下图所示。

算法思想:将图G中所有的顶点V分成两个顶点集合S和T。以v为源点已经确定了最短路径的终点并入S集合中,S初始时只含顶点v,T则是尚未确定到源点v最短路径的顶点集合。然后每次从T集合中选择S集合点中到T路径最短的那个点,并加入到集合S中,并把这个点从集合T删除。直到T集合为空为止。

在这里插入图片描述

function Dijkstra(Graph, source):
    create empty set S
    create a set Q containing all nodes
    create a map distance and set distance[source] = 0
    
    while Q is not empty:
        u = node in Q with smallest distance[u]
        remove u from Q
        add u to S
        
        for each neighbor v of u:
            if distance[u] + weight(u, v) < distance[v]:
                distance[v] = distance[u] + weight(u, v)
    
    return distance

算法复杂度:

  • 设带权有向图的边数为m,顶点数为n。
    • 用数组存储顶点方式实现复杂度为: O ( n 2 ) O(n^2) O(n2)
    • 用邻接表存储 + 二叉堆实现复杂度为: O ( ( m + n ) l o g n ) O((m+n)logn) O((m+n)logn)
    • 用邻接表存储 + 斐波那契堆实现复杂度为: O ( m + n l o g n ) O(m+nlogn) O(m+nlogn)

A*算法

A*算法结合了启发式搜索和Dijkstra算法的思想,用于在加权图中找到起点到目标节点的最短路径。它使用一个启发式函数来估计从当前节点到目标节点的距离,并根据这个估计值选择下一个要扩展的节点。

适用于带有启发式函数的加权图,找到起点到目标节点的最短路径。

function AStar(Graph, source, target):
    create empty set openSet and add source to it
    create empty set closedSet
    create a map gScore and set gScore[source] = 0
    create a map fScore and set fScore[source] = heuristic(source, target)
    
    while openSet is not empty:
        current = node in openSet with lowest fScore
        if current == target:
            return reconstructPath(cameFrom, current)
        
        remove current from openSet
        add current to closedSet
        
        for each neighbor of current:
            if neighbor is in closedSet:
                continue
            tentative_gScore = gScore[current] + distance(current, neighbor)
            
            if neighbor is not in openSet or tentative_gScore < gScore[neighbor]:
                cameFrom[neighbor] = current
                gScore[neighbor] = tentative_gScore
                fScore[neighbor] = gScore[neighbor] + heuristic(neighbor, target)
                if neighbor is not in openSet:
                    add neighbor to openSet
    
    return failure

Floyd算法

Floyd算法用于解决所有节点对之间的最短路径问题。它采用动态规划的思想,通过中间节点的遍历来更新任意两个节点之间的最短路径。

通过Floyd计算图G=(V,E)中各个顶点的最短路径时,需要引入一个矩阵S,矩阵S中的元素a[i][j]表示顶点i(第i个顶点)到顶点j(第j个顶点)的距离。

假设图G中顶点个数为N,则需要对矩阵S进行N次更新。初始时,矩阵S中顶点a[i][j]的距离为顶点 i 到顶点 j 的权值;如果 i 和 j 不相邻,则a[i][j]=∞。 接下来开始,对矩阵 S 进行N次更新

第1次更新时,如果"a[i][j]的距离" > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示" i 与 j 之间经过第1个顶点的距离"),则更新a[i][j]为"a[i][0]+a[0][j]“。 同理,第k次更新时,如果"a[i][j]的距离” > “a[i][k]+a[k][j]”,则更新a[i][j]为"a[i][k]+a[k][j]"。更新N次之后,操作完成!

在这里插入图片描述

function FloydWarshall(Graph):
    let dist be a matrix of size VxV, initialized with infinity
    for each edge (u, v) in Graph:
        dist[u][v] = weight(u, v)
    for k from 1 to V:
        for i from 1 to V:
            for j from 1 to V:
                if dist[i][k] + dist[k][j] < dist[i][j]:
                    dist[i][j] = dist[i][k] + dist[k][j]
    return dist

Bellman-Ford算法

Bellman-Ford算法用于在带有负权边的图中找到单源最短路径。它通过对边进行松弛操作来逐步优化到达每个节点的最短距离。解题思路就是假设有一条边 {begin,end,value} ,如果 dis[begin] + value < dis[end] ,我们可以更新 dis[end] 的值为 dis[begin] + value

Bellman-Ford不能计算有负权回路的图,因为在负权回路中,如果一直转圈的话,值就会一直变小。

在这里插入图片描述

function BellmanFord(Graph, source):
    create a list of size V called distance and set distance[source] = 0
    
    for i from 1 to V-1:
        for each edge (u, v) in Graph:
            if distance[u] + weight(u, v) < distance[v]:
                distance[v] = distance[u] + weight(u, v)
    
    for each edge (u, v) in Graph:
        if distance[u] + weight(u, v) < distance[v]:
            return "Graph contains a negative-weight cycle"
    
    return distance

SPFA算法

SPFA算法也用于在带有负权边的图中找到单源最短路径。它采用了队列来优化Bellman-Ford算法,通过动态选择要松弛的节点,减少了不必要的松弛操作,提高了算法的效率。

function SPFA(Graph, source):
    create a queue Q
    enqueue source into Q
    create a set visited and add source to it
    create a map distance and set distance[source] = 0
    
    while Q is not empty:
        current = dequeue from Q
        remove current from visited
        
        for each neighbor of current:
            if distance[current] + weight(current, neighbor) < distance[neighbor]:
                distance[neighbor] = distance[current] + weight(current, neighbor)
                if neighbor is not in visited:
                    enqueue neighbor into Q
                    add neighbor to visited
    
    return distance

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

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

相关文章

Spring Cloud分布式缓存

目录 单点Redis Redis数据持久化 RDB持久化 bgsave细节 RDB的缺点 AOF持久化 AOF的问题 RDB与AOF对比 搭建Redis主从架构 数据同步原理 全量同步 增量同步 主从同步优化 Redis哨兵 集群检测 选举主节点 故障转移 搭建哨兵集群 RedisTemplate的哨兵模式 单点…

【Leetcode】【每日一题】【中等】187. 重复的DNA序列 官方题解待更新

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/repeated-dna-sequences/descrip…

C++ AVL树 c语言版本

引入平衡树 假设我们有两个节点&#xff1a;当我们插入第三个节点&#xff0c;就失衡了&#xff1a;此刻我们就要把它平衡一下。 为什么要变平衡 为什么说它失衡了呢&#xff0c;又为什么要把它变平衡&#xff1f; 如图a&#xff0c;假设我们要查找30这个节点就要查3次才能…

耳机,耳麦,傻傻分不清,难怪麦克风没有声音

有时候会发现为什么同一根耳机线&#xff0c;插到笔记本上可以同时说话和收音&#xff0c;但是插到台式机就不行呢&#xff1f; 因为在以前&#xff0c;耳机和麦克风的接口都是独立的&#xff08;如上图&#xff09;。现在笔记本为了方便&#xff0c;就普遍使用了二合一接口&a…

正点原子嵌入式linux驱动开发——Linux 网络设备驱动

网络驱动是linux里面驱动三巨头之一&#xff0c;linux下的网络功能非常强大&#xff0c;嵌入式linux中也常常用到网络功能。前面已经讲过了字符设备驱动和块设备驱动&#xff0c;本章就来学习一下linux里面的网络设备驱动。 嵌入式网络简介 嵌入式下的网络硬件接口 本次笔记…

是时候放弃 Java 序列化了

基本概念 Java 序列化和反序列化三连问&#xff1a; 什么是 Java 序列化和反序列化&#xff1f;为什么需要 Java 序列化和反序列化&#xff1f;如何实现 Java 序列化和反序列化&#xff1f; 是什么 一句话就能够说明白什么是 Java 序列化和反序列化&#xff1f;Java 序列化…

【探索Linux】—— 强大的命令行工具 P.13(文件系统 | 软硬链接 | 动态库和静态库)

阅读导航 引言一、文件系统1. 磁盘文件系统2. 磁盘结构&#xff08;1&#xff09;物理结构&#xff08;2&#xff09;存储结构 3. stat 命令4. Linux ext2文件系统 二、软硬链接1. 软连接2. 硬链接 三、动态库和静态库1. 动态库&#xff08;1&#xff09;动态库文件扩展名&…

计算虚拟化1——CPU虚拟化

目录 vCPU的概念 vCPU和CPU的关系 CPU的Ring级别 CPU虚拟化技术 软件辅助全虚拟化 半虚拟化 硬件辅助虚拟化 计算资源的虚拟化可以分为CPU虚拟化、内存虚拟化、I/O虚拟化三个方面 CPU虚拟化&#xff1a;多个虚拟机共享CPU资源&#xff0c;对虚拟机中的敏感指令进行截获…

【JavaSE】基础笔记 - 类和对象(上)

目录 1、面向对象的初步认知 1.1、什么是面向对象 1.2、面向对象与面向过程 2. 类定义和使用 2.1、简单认识类 2.2、类的定义格式 2.3、自定义类举例说明 2.3.1、定义一个狗类 2.3.2、定义一个学生类 3、类的实例化 3.1、什么是实例化 3.2、类和对象的说明 1、面向…

MySQL性能优化的最佳20条经验

概述 关于数据库的性能&#xff0c;这并不只是DBA才需要担心的事。当我们去设计数据库表结构&#xff0c;对操作数据库时(尤其是查表时的SQL语句)&#xff0c;我们都需要注意数据操作的性能。下面讲下MySQL性能优化的一些点。 1. 为查询缓存优化你的查询 大多数的MySQL服务器…

Python基础入门例程47-NP47 牛牛的绩点(条件语句)

最近的博文&#xff1a; Python基础入门例程46-NP46 菜品的价格&#xff08;条件语句&#xff09;-CSDN博客 Python基础入门例程45-NP45 禁止重复注册&#xff08;条件语句&#xff09;-CSDN博客 Python基础入门例程44-NP44 判断列表是否为空&#xff08;条件语句&#xff0…

ElasticSearch 实现 全文检索 支持(PDF、TXT、Word、HTML等文件)通过 ingest-attachment 插件实现 文档的检索

一、Attachment 介绍 Attachment 插件是 Elasticsearch 中的一种插件&#xff0c;允许将各种二进制文件&#xff08;如PDF、Word文档等&#xff09;以及它们的内容索引到 Elasticsearch 中。插件使用 Apache Tika 库来解析和提取二进制文件的内容。通过使用 Attachment 插件&a…

redis数据库缓存服务器(基础命令)

redis比mysql访问数据快 非关系型数据库以键值对的方式存储数据 作用&#xff1a;加快访问速度&#xff0c;缓解数据库压力 redis最新版本7 特点 丰富的数据结构 list,set,hash等数据结构的存储 支持持久化 支持事务 “一个完整的动作&#xff0c;要么全部执行&#xff0…

数据结构:AVL树讲解(C++)

AVL树 1.AVL树的概念2.平衡因子3.节点的定义4.插入操作5.旋转操作&#xff08;重点&#xff09;5.1左单旋5.2右单旋5.3左右双旋5.4右左双旋 6.一些简单的测试接口7.完整代码 1.AVL树的概念 普通二叉搜索树&#xff1a;二叉搜索树 二叉搜索树虽可以缩短查找的效率&#xff0c;但…

D-Link监控账号密码信息泄露

访问漏洞的 url 为 /config/getuser?index0其中泄露了账号密码 使用泄露的账号密码登陆系统 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&#xff0c;万分感谢。 免责声明&#xff1a;由于传播或利用此文所提供的信息、技术或方法而造成的任何直接或间接的…

CCF-CSP真题《202309-3 梯度求解》思路+python,c++满分题解

想查看其他题的真题及题解的同学可以前往查看&#xff1a;CCF-CSP真题附题解大全 试题编号&#xff1a;202309-3试题名称&#xff1a;梯度求解时间限制&#xff1a;1.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 背景 西西艾弗岛运营公司近期在大力推广智能化市政管理系…

文本生成评估指标简单介绍BLEU+ROUGE+Perplexity+Meteor 代码实现

以下指标主要针对两种&#xff1a;机器翻译和文本生成&#xff08;文章生成&#xff09;&#xff0c;这里的文本生成并非是总结摘要那类文本生成&#xff0c;仅仅是针对生成句子/词的评价。 首先介绍BLEU&#xff0c;ROUGE, 以及BLEU的改进版本METEOR&#xff1b;后半部分介绍P…

volatile-禁重排案例详解

在每一个volatile写操作前面插入一个StoreStore屏障--->StoreStore屏障可以保证在volatile写之前&#xff0c;其前面所有的普通写操作都已经刷新到主内存中。 在每一个volatile写操作后面插入一个StoreLoad屏障--->StoreLoad屏障的作用是避免volatile写与后面可能有的vo…

【Qt之QtXlsx模块】安装及使用

1. 安装Perl&#xff0c;编译QtXlsx源码用 可以通过命令行进行查看是否已安装Perl。 下载及安装传送门&#xff1a;链接: https://blog.csdn.net/MrHHHHHH/article/details/134233707?spm1001.2014.3001.5502 1.1 未安装 命令&#xff1a;perl --version 显示以上是未安装…

测试面试题集-UI自动化测试

1、列举web自动化中常见的元素定位方式&#xff1f; id&#xff1a;根据id来获取元素&#xff0c;返回单个元素&#xff0c;id值一般是唯一的&#xff1b;name&#xff1a;根据元素的name属性定位&#xff1b;tagName&#xff1a;根据元素的标签名定位&#xff1b;className&a…