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

目录

  • 概念
  • 图遍历
    • 深度优先搜索 (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 visitedfor 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 Qenqueue start into Qmark start as visitedwhile Q is not empty:current = dequeue from Qfor each neighbor of current:if neighbor is not visited:mark neighbor as visitedenqueue 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 Screate a set Q containing all nodescreate a map distance and set distance[source] = 0while Q is not empty:u = node in Q with smallest distance[u]remove u from Qadd u to Sfor 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 itcreate empty set closedSetcreate a map gScore and set gScore[source] = 0create a map fScore and set fScore[source] = heuristic(source, target)while openSet is not empty:current = node in openSet with lowest fScoreif current == target:return reconstructPath(cameFrom, current)remove current from openSetadd current to closedSetfor each neighbor of current:if neighbor is in closedSet:continuetentative_gScore = gScore[current] + distance(current, neighbor)if neighbor is not in openSet or tentative_gScore < gScore[neighbor]:cameFrom[neighbor] = currentgScore[neighbor] = tentative_gScorefScore[neighbor] = gScore[neighbor] + heuristic(neighbor, target)if neighbor is not in openSet:add neighbor to openSetreturn 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 infinityfor 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] = 0for 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 Qenqueue source into Qcreate a set visited and add source to itcreate a map distance and set distance[source] = 0while Q is not empty:current = dequeue from Qremove current from visitedfor 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 Qadd neighbor to visitedreturn distance

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

挑战100天 AI In LeetCode Day01(2)

挑战100天 AI In LeetCode Day01&#xff08;2&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-22.1 题目2.2 题解 三、面试经典 150 题-23.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&#xff0c;面向程序…

基于nodejs+vue贝佳月子会所服务平台系统- 计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

ESP32S3入手体验测试

ESP32S3入手体验测试 &#x1f516;所入手的型号是YD-ESP32-S3 N16R8,该款和乐鑫官方推出的ESP32-S3-DevKitC-1配置差不多。 &#x1f388;乐鑫官方介绍&#xff1a;ESP32-S3-DevKitC-1 v1.1 &#x1f530;两者采用的模组&#xff1a;ESP32-S3-WROOM-1 和ESP32-S3-WROOM-1U模组…

Maven修改仓库和镜像地址

目录 1、修改仓库地址2、修改镜像地址 1、修改仓库地址 使用IDEA时,如果不指定自己下载的Maven,idea会默认使用自带的Maven 3&#xff08;bundle)。maven 3默认的仓库路径一般是在c盘的用户文件夹中的.m2目录下&#xff1a; 当maven下的pom文件中的依赖逐渐增加时,maven仓库下…

云安全—kubelet攻击面

0x00 前言 虽然说总结的是kubelet的攻击面&#xff0c;但是在总结攻击面之前还是需要去了解kubelet的基本原理&#xff0c;虽然说我们浅尝即止&#xff0c;但是还是要以能给别人讲出来为基本原则。 其他文章: 云安全—K8s APi Server 6443 攻击面云安全—K8S API Server 未授…

基于ASP.NET MVC + Bootstrap的仓库管理系统

基于ASP.NET MVC Bootstrap的仓库管理系统。源码亲测可用&#xff0c;含有简单的说明文档。 适合单仓库&#xff0c;基本的仓库入库管理&#xff0c;出库管理&#xff0c;盘点&#xff0c;报损&#xff0c;移库&#xff0c;库位等管理&#xff0c;有着可视化图表。 系统采用Bo…

懒汉模式和饿汉模式

目录 单例模式 饿汉模式 懒汉模式 单例模式 所谓单例模式,就是在有些场景中,有些特定的类,只能创建一个实例(对象),当程序员不小心创建多个实例,就会出现编译报错. ★ 这种模式涉及到一个单一的类&#xff0c;该类负责创建自己的对象&#xff0c;同时确保只有单个对象被创…

试利用栈的基本操作写出先序遍历二叉树的非递归形式的算法

试利用栈的基本操作写出先序遍历二叉树的非递归形式的算法 代码思路&#xff1a; 要用栈解决先序遍历&#xff0c;我们首先要知道栈的性质和二叉树先序遍历的规则 栈最基本的就是先进后出 而二叉树先序遍历就是“根左右” 利用这两个性质&#xff0c;我们可以先将根结点入队…

ActiveMq学习⑧__ActiveMQ的消息持久化机制

ActiveMQ的消息存储和持久化 MQ的高可用 事务持久签收可持久化 &#xff08;类似于与mq消息的同步机制&#xff09; 为了避免意外宕机以后丢失信息&#xff0c;需要做到重启后可以恢复消息队列&#xff0c;消息系统一半都会采用持久化机制。 ActiveMQ的消息持久化机制 Act…

UE5——源码阅读——3——引擎退出

这边主要是做了个标记&#xff0c;为了UE的性能分析 把全局运行设置为0&#xff0c;把日志也设置为空 判断预加载屏幕 关闭visual logger 关闭资源编译的管理器 引擎预退出 预退出的核心代理 关闭网络追踪 关闭所有电影场景的捕捉接口 关闭UE中用于MID的缓存 关闭引擎…

【Spring Security】Spring Security 认证与授权

在前面的章节中,我们沿用了Spring Security默认的安全机制:仅有一个用户,仅有一种角色。在实际开发中,这自然是无法满足需求的。本章将更加深入地对Spring Security迚行配置,且初步使用授权机制。 3.1 默认数据库模型的认证与授权 3.1.1、资源准备 首先,在controller包…

Java8实战-总结46

Java8实战-总结46 CompletableFuture&#xff1a;组合式异步编程让代码免受阻塞之苦使用 CompletableFuture 发起异步请求寻找更好的方案 CompletableFuture&#xff1a;组合式异步编程 让代码免受阻塞之苦 使用 CompletableFuture 发起异步请求 可以使用工厂方法supplyAsyn…

51单片机汇编-点亮一个led

文章目录 前言1.打开IDE2.设置编辑器3.设置输出4. 原理图5.编写代码6 编译7.下载8.其它代码1.LED闪烁2.跑马灯 前言 51单片机基础 本章主要介绍打开一个led,具体采用51汇编 1.打开IDE 选择STC89C52RC 后缀是.asm 2.设置编辑器 3.设置输出 4. 原理图 5.编写代码 ORG 00H;伪代…

Webpack的Tree Shaking。它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Web前端—网页制作(以“学成在线”为例)

版本说明 当前版本号[20231105]。 版本修改说明20231105初版 目录 文章目录 版本说明目录day07-学成在线01-项目目录02-版心居中03-布局思路04-header区域-整体布局HTML结构CSS样式 05-header区域-logo06-header区域-导航HTML结构CSS样式 07-header区域-搜索布局HTML结构CSS…

MongoDB设置密码

关于为什么要设置密码 公司的测试服务器MongoDB服务对外网开放的&#xff0c;结果这几天发现数据库被每天晚上被人清空的了&#xff0c;还新建了个数据库&#xff0c;说是要支付比特币。查了日志看到有个境外的IP登录且删除了所有的集合。所以为了安全起见&#xff0c;我们给m…

企业级SpringBoot单体项目模板 —— 使用 AOP + JWT实现登陆鉴权

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;SpringBoot、企业级、项目模板☀️每日 一言&#xff1a;没学会走就学跑从来都不是问题&#xff0c;要问问自己是不是天才&#xff0c;如果不是&#xff0c;那就要一步步来 文章目录 使用JWT实现…

python用cv2画图(line, rectangle, text等)

Python做图像图形研究的时候&#xff0c;通常需要画很多辅助几何形状&#xff08;比如bounding box等&#xff09;。基于opencv的几何图形绘制具有易用性&#xff0c;而且天然能和numpy数组交互。 本文总结了几种常用的cv2画几何图形的方法&#xff0c;当一个简易的手册使用&a…

飞书开发学习笔记(三)-利用python开发调试云文档和电子表格

飞书开发学习笔记(三)-利用python开发调试云文档和电子表格 一.建立Python飞书开发环境 首先还是进入开放平台下的API调试台 飞书开放平台&#xff1a;https://open.feishu.cn/app?langzh-CN 以获取"我的空间"下的文件清单为例&#xff0c;通过获取飞书API调试台提…

canvas实现刮奖功能

canvas刮奖原理很简单&#xff0c;就是在刮奖区添加两个canvas&#xff0c;第一个canvas用于显示刮开后显示的内容&#xff0c;可以是一张图片或一个字符串&#xff0c;第二个canvas用于显示涂层&#xff0c;可以用一张图片或用纯色填充&#xff0c;第二个canvas覆盖在第一个ca…