当前位置: 首页 > news >正文

【数据结构】图的遍历:广度优先(BFS),深度优先(DFS)

目录

1、广度优先(BFS)

算法思想 

广度优先生成树 

知识树 

代码实现 

2、深度优先(DFS)

算法思想 

深度优先生成树

知识树 

代码实现 


1、广度优先(BFS)

算法思想 

         图的广度优先遍历(BFS)是一种遍历图的算法,其思想是从起始顶点开始遍历图,先访问起始顶点的所有直接邻居,然后遍历这些邻居的直接邻居,以此类推,直到遍历完整个图。

BFS算法需要使用一个队列来保存已经遍历过但还未访问其邻接顶点。具体步骤如下:

  1. 将起始顶点加入队列中,并标记为已访问。
  2. 从队列中取出一个顶点V,并依次访问V的所有未被访问的邻接顶点,并将这些邻接顶点加入队列中,并标记为已访问。
  3. 重复步骤2,直到队列为空。

广度优先生成树 

         广度优先搜索(BFS)可以用来生成一棵图的广度优先生成树(BFS树),该树的根节点为起始节点,其余节点按照宽度优先的顺序依次加入。BFS树可以用来解决最短路径问题,以及其他需要按照距离或层次访问节点的问题。

具体的实现步骤如下:

  1. 初始化BFS树,将起始节点加入树中。
  2. 将起始节点加入待访问队列。
  3. 对于队列中的每个节点,依次遍历其所有邻居节点。
  4. 对于每个邻居节点,如果该节点还未加入BFS树,则将其加入,并将该邻居节点的父节点设为当前节点。
  5. 将已访问的节点从队列中移除。
  6. 重复步骤3-5,直到队列为空。

知识树 

 

代码实现 

 下面是C语言实现BFS的示例代码:

#include <stdio.h>
#include <stdlib.h>#define MAXV 100  // 最大顶点数typedef struct {int edges[MAXV][MAXV];  // 邻接矩阵int n;  // 顶点数
} Graph;typedef struct {int data[MAXV];int front, rear;
} Queue;int visited[MAXV];  // 标记已经遍历的结点void initQueue(Queue* q) {q->front = q->rear = 0;
}void enqueue(Queue* q, int x) {q->data[q->rear++] = x;
}int dequeue(Queue* q) {return q->data[q->front++];
}int isEmpty(Queue* q) {return q->front == q->rear;
}void initGraph(Graph* g, int n) {g->n = n;for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)g->edges[i][j] = 0;
}void addEdge(Graph* g, int u, int v) {g->edges[u][v] = 1;g->edges[v][u] = 1;
}void bfs(Graph* g, int u) {Queue* q = (Queue*) malloc(sizeof(Queue));initQueue(q);visited[u] = 1;printf("%d ", u);enqueue(q, u);while (!isEmpty(q)) {int v = dequeue(q);for (int w = 0; w < g->n; w++) {if (g->edges[v][w] && !visited[w]) {visited[w] = 1;printf("%d ", w);enqueue(q, w);}}}
}int main() {Graph g;int n, m, u, v;printf("输入顶点数和边数:");scanf("%d %d", &n, &m);initGraph(&g, n);printf("输入每条边的两个端点:\n");for (int i = 0; i < m; i++) {scanf("%d %d", &u, &v);addEdge(&g, u, v);}printf("输入起始顶点:");scanf("%d", &u);printf("广度优先遍历结果:");bfs(&g, u);printf("\n");return 0;
}

        首先定义了一个邻接矩阵表示图,以及一个队列来存放待遍历的顶点。初始化队列为空,然后将起始顶点加入队列,并标记为已访问。然后开始遍历队列中的顶点,对于每个顶点,遍历其未访问的邻居,将其添加到队列中,并标记为已访问。代码中使用了visited数组来标记顶点是否已经被访问过了。

在以上代码中,输入格式为:

5 6
0 1
0 2
1 2
2 3
1 3
3 4
0

其中第一行为总顶点数和总边数,第2~m+1行为每条边的两个端点,然后输入起始顶点编号。

2、深度优先(DFS)

算法思想 

        图的深度优先遍历(Depth-First Search,DFS)是一种遍历图的算法。其基本思想是从一个顶点开始,沿着一条路径一直走到底,直到所有的路径都被探索过为止。如果还有顶点未被访问,则回溯到前一个顶点,继续搜索下一条路径,直到所有的顶点都被访问为止。

具体实现过程如下:
1. 从某一顶点开始遍历,将该顶点标记为已访问。
2. 对当前访问的顶点的所有未访问的邻接顶点进行访问,即从当前顶点的邻接顶点开始深度优先遍历。
3. 重复步骤2,直到所有的顶点都被访问。

        图的深度优先遍历可以用递归或栈来实现。在递归实现中,每次访问一个顶点时,递归地访问其未访问的邻接顶点,直到所有的顶点都被访问。在栈实现中,首先将起始顶点入栈,然后对栈内的顶点进行出栈、访问、入栈操作,直到所有的顶点都被访问。

深度优先生成树

        深度优先生成树(depth first search tree)是一棵以图中某个顶点为根的深度优先遍历树,它的生成过程为:

  1. 选择图中任意一个未被遍历的顶点作为根节点;
  2. 以根节点为起点进行深度优先遍历;
  3. 遍历到一个未被遍历的节点时,将该节点加入到生成树中,并将其父节点与该节点之间的边添加到生成树中;
  4. 如果图中还存在未被遍历的节点,则在剩余未被遍历的节点中选择一个节点作为新的根节点,并重复上述过程。

        生成树的过程可以通过递归实现,也可以使用栈来实现。在遍历的过程中,需要记录每个节点的状态,即已被发现、已被访问或未被发现。

知识树 

 

代码实现 

 以下是C语言中实现图的深度优先遍历的代码:

#include <stdio.h>
#include <stdbool.h>#define MAX_VERTEX_NUM 100  // 顶点最大数量typedef struct {int vertex;  // 顶点int next;    // 指向下一个邻接点的指针
} EdgeNode;typedef struct {int vertex;      // 顶点EdgeNode *edge;  // 指向邻接点链表的指针
} VertexNode;VertexNode graph[MAX_VERTEX_NUM];  // 图
bool visited[MAX_VERTEX_NUM];      // 记录哪些顶点已经被访问过void addEdge(int v1, int v2) {// 添加边(v1, v2)EdgeNode *edge = graph[v1].edge;if (edge == NULL) {graph[v1].edge = (EdgeNode *) malloc(sizeof(EdgeNode));graph[v1].edge->vertex = v2;graph[v1].edge->next = -1;} else {while (edge->next != -1) {edge = graph[v1].edge + edge->next;}edge->next = graph[v1].edge - edge + addEdge(v2, -1);}
}void dfs(int vertex) {visited[vertex] = true;printf("%d ", vertex);EdgeNode *edge = graph[vertex].edge;while (edge != NULL) {int nextVertex = edge->vertex;if (!visited[nextVertex]) {dfs(nextVertex);}edge = graph[vertex].edge + edge->next;}
}int main() {int n, m;scanf("%d %d", &n, &m);  // n表示顶点数,m表示边数for (int i = 1; i <= n; i++) {graph[i].vertex = i;}for (int i = 0; i < m; i++) {int v1, v2;scanf("%d %d", &v1, &v2);addEdge(v1, v2);addEdge(v2, v1);  // 在无向图中,边(v1, v2)和边(v2, v1)都要添加}memset(visited, false, MAX_VERTEX_NUM);  // 初始化visited数组printf("DFS: ");dfs(1);  // 从顶点1开始进行DFSreturn 0;
}

        其中addEdge函数用于添加一条边。在main函数中,先读入图的顶点数和边数,然后依次读入每条边,并调用addEdge函数添加边。最后,初始化visited数组为false,并从顶点1开始进行深度优先遍历。

相关文章:

【数据结构】图的遍历:广度优先(BFS),深度优先(DFS)

目录 1、广度优先&#xff08;BFS&#xff09; 算法思想 广度优先生成树 知识树 代码实现 2、深度优先&#xff08;DFS&#xff09; 算法思想 深度优先生成树 知识树 代码实现 1、广度优先&#xff08;BFS&#xff09; 算法思想 图的广度优先遍历&#xff0…...

Mysql 学习总结(89)—— Mysql 库表容量统计

前言 统计每个库每个表的大小是数据治理中最简单的一个要求,下面从抽样统计结果及精确统计结果两方面来统计MySQL的每个库每个表的数据量情况。mysql 数据字典库 information_schema 里记录了统计的预估数据量(innodb 引擎表不准确,MyISAM 引擎表准确)及数据大小、索引大小及…...

virtualBox安装配置使用

virtualBox下载 //官网下载地址 https://www.virtualbox.org/wiki/Downloads ​ //ubuntu下载地址 https://cn.ubuntu.com/download/server/step1 virtualBox使用 导入现有镜像 &#xff08;如果报错可以降低系统配置&#xff0c;因为有些主机可能不支持高配置&#xff0c;例如…...

北斗导航 | RTD、RTK完好性之B值、VPL与HPL计算(附B值计算matlab源代码)

===================================================== github:https://github.com/MichaelBeechan CSDN:https://blog.csdn.net/u011344545 ===================================================== 1、S矩阵获取 为第i颗卫星测距标准差:...

more often than not 的含义

今天听https://www.bilibili.com/video/BV1w94y12727/?p2&spm_id_frompageDriver more often than not 连读:mor ofen than au 想了半天不动什么意思. 查了一下表示大部分情况下. 还是不理解为什么, 就查了必应里面的词典. 表示超过一半的情况下. 又自己想了想突然懂了.…...

【Linux】Linux环境配置安装

目录 一、双系统&#xff08;特别不推荐&#xff09; 安装双系统的缺点&#xff1a; 安装双系统优点&#xff08;仅限老手&#xff09;&#xff1a; 二、虚拟机centos7镜像&#xff08;较为推荐推荐&#xff09; 虚拟机的优点&#xff1a; 虚拟机的缺点&#xff1a; ​ …...

从零学习开发一个RISC-V操作系统(二)丨GCC编译器和ELF格式

本篇文章的内容 一、GCC&#xff08;GUN Compiler Collection&#xff09;1.1 GCC的命令格式1.2 GCC的主要执行步骤1.3 GCC涉及的文件类型 二、ELF简介2.1 ELF文件格式图2.2 ELF文件处理的相关工具2.3 练习 本系列是博主参考B站课程学习开发一个RISC-V的操作系统的学习笔记&…...

论文阅读_大语言模型_Llama2

英文名称: Llama 2: Open Foundation and Fine-Tuned Chat Models 中文名称: Llama 2&#xff1a;开源的基础模型和微调的聊天模型 文章: http://arxiv.org/abs/2307.09288 代码: https://github.com/facebookresearch/llama 作者: Hugo Touvron 日期: 2023-07-19 引用次数: 11…...

当量因子法、InVEST、SolVES模型等多技术融合在生态系统服务功能社会价值评估中的应用及论文写作、拓展分析

生态系统服务是人类从自然界中获得的直接或间接惠益&#xff0c;可分为供给服务、文化服务、调节服务和支持服务4类&#xff0c;对提升人类福祉具有重大意义&#xff0c;且被视为连接社会与生态系统的桥梁。自从启动千年生态系统评估项目&#xff08;Millennium Ecosystem Asse…...

k8s Limits 限制内存

Limits 限制内存 在 Kubernetes (K8s) 中&#xff0c;可以使用 Limits&#xff08;资源限制&#xff09;来限制 Pod&#xff08;容器&#xff09;使用的内存数量。此处的 Limits 表示 Pod 在 K8s 集群中可用的最大内存量。一旦 Pod 内存使用超过这个限制&#xff0c;可能会触发…...

单片机第三季-第三课:STM32开发板原理图、配置、浮点运算单元

目录 1&#xff0c;开发板原理图 2&#xff0c;浮点运算单元&#xff08;FPU&#xff09; 1&#xff0c;开发板原理图 课程视频比较早&#xff0c;介绍了三款开发板。观看视频时用的开发板说和51单片机共板的STM32核心板&#xff0c;将51单片机从底座拆下来后&#xff0c;安…...

观察者模式 发布-订阅模式(设计模式与开发实践 P8)

文章目录 观察者模式运用实现 观察者模式 定义&#xff1a;他用来定义对象之间一种一对多的依赖关系&#xff0c;当一个对象状态发生改变时&#xff0c;所有依赖他的对象都会得到通知 运用 如果我们使用过 DOM 上的事件函数&#xff0c;那就接触过观察者模式 document.body…...

【日常业务开发】Java实现异步编程

【日常业务开发】Java实现异步编程 Java实现异步编程什么是异步异步的八种实现方式异步编程线程异步Future异步CompletableFuture实现异步Spring的Async异步Spring ApplicationEvent事件实现异步消息队列ThreadUtil异步工具类Guava异步 CompletableFuture异步编排工具类创建异步…...

学习笔记|模数转换器|ADC原理|STC32G单片机视频开发教程(冲哥)|第十七集:ADC采集

文章目录 1.模数转换器&#xff08;ADC&#xff09;是什么&#xff1f;手册说明&#xff1a; 2.STC32G单片机ADC使用原理19.1.1 ADC控制寄存器&#xff08;ADC_CONTR)19.1.2 ADC配置寄存器&#xff08;ADCCFG)19.1.4ADC时序控制寄存器&#xff08;ADCTIM&#xff09;19.3 ADC相…...

OpenCV实现“蓝线挑战“特效

原理 算法原理可以分为三个流程&#xff1a; 1、将视频&#xff08;图像&#xff09;从&#xff08;顶->底&#xff09;或&#xff08;左->右&#xff09;逐行&#xff08;列&#xff09;扫描图像。 2、将扫描完成的行&#xff08;列&#xff09;像素重新生成定格图像…...

容器管理工具 Docker生态架构及部署

目录 一、Docker生态架构 1.1 Docker Containers Are Everywhere 1.2 生态架构 1.2.1 Docker Host 1.2.2 Docker daemon 1.2.3 Registry 1.2.4 Docker client 1.2.5 Image 1.2.6 Container 1.2.7 Docker Dashboard 1.3 Docker版本 二、Docker部署 2.1 使用YUM源部署…...

js判断数据类型的方法

简单数据类型用&#xff1a;typeof&#xff0c; // 可以直接typeof空格接数据的方式,也可以typeof(数据)的方式使用 console.log(typeof ""); //string(检验字符串没问题) console.log(typeof 1); //number(检验数字没问题) console.log(typ…...

达梦数据库随系统开机自动启动脚本

写一个脚本&#xff0c;实现在服务器开机后自动启动达梦数据库的功能。 1. 在/etc/init.d/目录下&#xff0c;编写脚本&#xff0c;并将脚本命名为startdm.sh。脚本内容实现如下&#xff1a; #!/bin/bash #chkconfig:2345 80 90 #decription:启动达梦# 切换到 dmdba 用户 su …...

Python开发利器之VS Code

Python官方提供了一个Python集成开发环境&#xff08;IDE&#xff09;&#xff1a; IDLE (Integrated Development and Learning Environment)。 它提供了一个图形用户界面&#xff0c;可以让开发者编写、调试和执行Python程序。IDLE包含Python解释器、代码编辑器、调试器和文件…...

【Axure视频教程】输入框控制滑动评分条

今天教大家在Axure里如何制作输入框控制滑动评分条的原型模板&#xff0c;可以通过鼠标左右拖动滑块&#xff0c;也可以点击条形让滑块移动到指定位置&#xff0c;标签和输入框里会返回具体的分值&#xff0c;分值由滑块所在的位置动态计算而成&#xff1b;也可以在输入框里输入…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

使用LangGraph和LangSmith构建多智能体人工智能系统

现在&#xff0c;通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战&#xff0c;比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

Qt 事件处理中 return 的深入解析

Qt 事件处理中 return 的深入解析 在 Qt 事件处理中&#xff0c;return 语句的使用是另一个关键概念&#xff0c;它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别&#xff1a;不同层级的事件处理 方…...

深入浅出Diffusion模型:从原理到实践的全方位教程

I. 引言&#xff1a;生成式AI的黎明 – Diffusion模型是什么&#xff1f; 近年来&#xff0c;生成式人工智能&#xff08;Generative AI&#xff09;领域取得了爆炸性的进展&#xff0c;模型能够根据简单的文本提示创作出逼真的图像、连贯的文本&#xff0c;乃至更多令人惊叹的…...

OCR MLLM Evaluation

为什么需要评测体系&#xff1f;——背景与矛盾 ​​ 能干的事&#xff1a;​​ 看清楚发票、身份证上的字&#xff08;准确率>90%&#xff09;&#xff0c;速度飞快&#xff08;眨眼间完成&#xff09;。​​干不了的事&#xff1a;​​ 碰到复杂表格&#xff08;合并单元…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)

引言 在嵌入式系统中&#xff0c;用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例&#xff0c;介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单&#xff0c;执行相应操作&#xff0c;并提供平滑的滚动动画效果。 本文设计了一个…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...