CSP-J 算法基础 广度优先搜索BFS

文章目录

  • 前言
  • 广度优先搜索是什么
  • 广度优先搜索的实现
  • BFS 的具体编程实现
  • 举例:广度优先搜索的具体步骤
    • 初始状态:
    • 步骤 1:加入起点节点 1
    • 步骤 2:访问队列中的节点 1,加入其邻居节点 2 和 4
    • 步骤 3:访问队列中的节点 2,加入其未访问的邻居节点 3
    • 步骤 4:访问队列中的节点 4,发现它的邻居(节点 1 和 3)都已访问,跳过
    • 步骤 5:访问队列中的节点 3,发现它的邻居(节点 2 和 4)都已访问,跳过
  • 编程实现BFS广度优先搜索
      • C 语言代码示例
      • 代码解释
      • 总结
  • 总结


前言

广度优先搜索(Breadth-First Search,简称 BFS)是图论中的一种基础算法,用于遍历或搜索图的节点。与深度优先搜索(DFS)不同,BFS 是一种层次化的搜索方式,优先访问距离起始节点最近的节点,逐层扩展到更远的节点。由于其遍历顺序的特点,BFS 经常被用于解决最短路径问题、图的连通性检查、树的层序遍历等问题。

在算法竞赛如 CSP-J 中,掌握 BFS 能帮助我们高效地解决图论相关的题目,尤其是在寻找最短路径、求解无权图的某些属性时,BFS 是一种非常有效的工具。


广度优先搜索是什么

BFS 是一种图的遍历算法,类似于按层次的方式搜索图。它从起始节点开始,首先访问所有与该节点直接相邻的节点,然后依次访问每个已访问节点的邻接节点,直到遍历完所有节点或找到目标节点。

BFS 的特点是按最短路径进行遍历。在无权图中,BFS 可以保证从起点到某个节点的路径是最短的。它广泛应用于路径搜索、迷宫问题、连通性检查等场景。

广度优先搜索的实现

BFS 的核心思想是使用队列(FIFO,先进先出)来实现按层次的搜索。具体实现步骤如下:

  1. 初始化:选择一个起始节点,将其标记为已访问并加入队列。
  2. 遍历:从队列中取出一个节点,检查其所有未访问的邻接节点,将它们标记为已访问并加入队列。
  3. 重复:不断从队列中取出节点并访问其邻接节点,直到队列为空。

通过这种方式,BFS 能逐层遍历图的节点,确保从起点到任意节点的访问顺序是按最短路径进行的。

BFS 的具体编程实现

在编程中,BFS 通常使用以下数据结构来实现:

  • 队列:用于保存当前层次要访问的节点。
  • 访问标记数组:用于记录每个节点是否已经访问过,避免重复访问。
  • 图的表示方式:通常使用邻接表或邻接矩阵来存储图的结构信息。

BFS 的伪代码步骤如下:

  1. 将起点加入队列,并将其标记为已访问。
  2. 当队列不为空时,取出队列的第一个节点,检查该节点所有邻接节点。
  3. 对于每个未访问的邻接节点,将其标记为已访问,并加入队列。
  4. 重复该过程,直到队列为空或找到目标节点。

举例:广度优先搜索的具体步骤

我们通过一个简单的例子来演示 BFS 的具体操作步骤。假设有一个无向图,如下:

    1 —— 2|     |4 —— 3

我们从节点 1 开始进行广度优先搜索,目标是遍历所有节点。

初始状态:

  • 队列:空
  • 访问标记数组:所有节点未访问
  • 起点:1

步骤 1:加入起点节点 1

  • 队列:[1]
  • 标记:节点 1 标记为已访问

步骤 2:访问队列中的节点 1,加入其邻居节点 2 和 4

  • 队列:[2, 4]
  • 标记:节点 1、2、4 已访问

步骤 3:访问队列中的节点 2,加入其未访问的邻居节点 3

  • 队列:[4, 3]
  • 标记:节点 1、2、3、4 已访问

步骤 4:访问队列中的节点 4,发现它的邻居(节点 1 和 3)都已访问,跳过

  • 队列:[3]
  • 标记:不变

步骤 5:访问队列中的节点 3,发现它的邻居(节点 2 和 4)都已访问,跳过

  • 队列:空
  • 标记:不变

至此,所有节点都已访问,BFS 结束。

编程实现BFS广度优先搜索

下面是一个简单的广度优先搜索(BFS)的 C 语言代码示例。这段代码实现了一个无向图的 BFS 遍历,展示了如何使用邻接表存储图,并进行 BFS 遍历。

C 语言代码示例

#include <stdio.h>
#include <stdlib.h>// 链表节点表示边
typedef struct AdjListNode {int dest;  // 邻居顶点struct AdjListNode* next;  // 指向下一个邻接节点
} AdjListNode;// 顶点的邻接表
typedef struct AdjList {AdjListNode* head;  // 链表头指针
} AdjList;// 图结构
typedef struct {int numVertices;  // 顶点数AdjList* array;  // 邻接表数组
} Graph;// 创建链表节点
AdjListNode* createNode(int dest) {AdjListNode* newNode = (AdjListNode*)malloc(sizeof(AdjListNode));newNode->dest = dest;newNode->next = NULL;return newNode;
}// 初始化图
Graph* createGraph(int numVertices) {Graph* graph = (Graph*)malloc(sizeof(Graph));graph->numVertices = numVertices;graph->array = (AdjList*)malloc(numVertices * sizeof(AdjList));for (int i = 0; i < numVertices; i++) {graph->array[i].head = NULL;}return graph;
}// 添加无向边
void addEdge(Graph* graph, int src, int dest) {// 添加 src -> destAdjListNode* newNode = createNode(dest);newNode->next = graph->array[src].head;graph->array[src].head = newNode;// 添加 dest -> src (无向图)newNode = createNode(src);newNode->next = graph->array[dest].head;graph->array[dest].head = newNode;
}// 广度优先搜索
void BFS(Graph* graph, int startVertex) {// 创建访问标记数组int* visited = (int*)malloc(graph->numVertices * sizeof(int));for (int i = 0; i < graph->numVertices; i++) {visited[i] = 0;  // 初始化为未访问}// 创建队列int* queue = (int*)malloc(graph->numVertices * sizeof(int));int front = 0;int rear = 0;// 标记起始节点为已访问,并将其入队visited[startVertex] = 1;queue[rear++] = startVertex;while (front < rear) {// 出队int currentVertex = queue[front++];printf("访问顶点 %d\n", currentVertex);// 遍历所有邻接节点AdjListNode* adjList = graph->array[currentVertex].head;while (adjList != NULL) {int adjVertex = adjList->dest;if (!visited[adjVertex]) {visited[adjVertex] = 1;  // 标记为已访问queue[rear++] = adjVertex;  // 入队}adjList = adjList->next;}}// 释放内存free(visited);free(queue);
}// 主函数
int main() {int numVertices = 5;Graph* graph = createGraph(numVertices);// 添加边addEdge(graph, 0, 1);addEdge(graph, 0, 4);addEdge(graph, 1, 2);addEdge(graph, 1, 3);addEdge(graph, 1, 4);addEdge(graph, 2, 3);addEdge(graph, 3, 4);// 从顶点 0 开始进行 BFS 遍历printf("广度优先搜索结果:\n");BFS(graph, 0);// 释放内存for (int i = 0; i < numVertices; i++) {AdjListNode* node = graph->array[i].head;while (node) {AdjListNode* temp = node;node = node->next;free(temp);}}free(graph->array);free(graph);return 0;
}

代码解释

  1. 数据结构定义

    • AdjListNode:表示图中每条边的链表节点。
    • AdjList:表示每个顶点的邻接链表。
    • Graph:包含邻接表数组和顶点数的图结构。
  2. 图的初始化

    • createNode:创建链表节点。
    • createGraph:初始化图,创建邻接表数组。
    • addEdge:添加无向边,更新源顶点和目标顶点的邻接表。
  3. BFS 实现

    • 初始化访问标记数组和队列。
    • 从起始节点开始,标记为已访问并入队。
    • 逐层访问图的节点,并将未访问的邻接节点入队。
    • 打印每个访问到的节点。
  4. 主函数

    • 创建图,添加边,调用 BFS 函数,并释放内存。

总结

这段代码演示了如何用 C 语言实现广度优先搜索(BFS)算法。通过邻接表存储图,BFS 遍历每个节点,并按层次访问所有邻接节点。掌握 BFS 的实现可以帮助我们高效解决图论中的许多问题,如最短路径查找、连通性检测等。


总结

广度优先搜索(BFS)是一种重要的图遍历算法,它通过队列的方式,按层次访问图的节点,确保遍历顺序是按最短路径进行的。BFS 特别适用于无权图中的最短路径查找、图的连通性检测等问题。在实际编程中,我们利用队列、访问标记数组等简单的数据结构来实现 BFS 的逻辑,并通过例子演示了该算法的逐步执行过程。

掌握 BFS 能让我们更加高效地解决与图相关的各种问题,无论是在竞赛中,还是在实际开发中,BFS 都是一个非常有用的工具。

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

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

相关文章

Java | Leetcode Java题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; class Solution {public String toHex(int num) {if (num 0) {return "0";}StringBuffer sb new StringBuffer();for (int i 7; i > 0; i --) {int val (num >> (4 * i)) & 0xf;if (sb.length() > 0 || val …

开发后台管理系统-开发环境搭建

文章目录 需求设计环境搭建创建项目工程测试结果 安装Element Plus安装路由安装Vue Router配置Vue Router 测试 需求 开发一个后台管理系统 这里以CDN后台管理系统为例 设计 参照 CDN后台管理系统功能说明文档 环境搭建 确保已经安装了Node.js和npm 执行 npm install -g vu…

映射map

Hello,大家好&#xff0c;我是菜就多练&#xff0c;输不起就别玩&#xff0c;今天我们来讲映射。 由于近期有事&#xff0c;所以停更了一段时间&#xff0c;请大家谅解。 在 C 标准模板库&#xff08;STL&#xff09;中&#xff0c;map 是一种关联容器&#xff0c;它存储键值…

Android 12系统源码_窗口管理(八)WindowConfiguration的作用

前言 在Android系统中WindowConfiguration这个类用于管理与窗口相关的设置&#xff0c;该类存储了当前窗口的显示区域、屏幕的旋转方向、窗口模式等参数&#xff0c;应用程序通过该类提供的信息可以更好的适配不同的屏幕布局和窗口环境&#xff0c;以提高用户体验。 一、类定…

水库监测布点的核心要求与策略解析

在水库的安全监测体系中&#xff0c;监测点位的合理布置是确保数据准确性和监测效果的关键。涵盖了常规监测、形变监控、应力分析以及地质灾害预警等多个维度&#xff0c;其中&#xff0c;形变监测尤为关键&#xff0c;直接关乎大坝的安全状态。形变监测通过测斜仪相关的传感器…

Qt开发技巧(四)“tr“使用,时间类使用,Qt容器取值,类对象的删除,QPainter画家类,QString的转换,用好 QVariant类型

继续讲一些Qt技巧操作 1.非必要不用"tr" 如果程序运行场景确定是某一固定语言&#xff0c;就不需要用tr,"tr"之主要针对多语种翻译的&#xff0c;因为tr的本意是包含英文&#xff0c;然后翻译到其他语言比如中文&#xff0c;不要滥用tr&#xff0c;如果没有…

【渗透测试】——DVWA靶场搭建

&#x1f4d6; 前言&#xff1a;DVWA&#xff08;Damn Vulnerable Web Application&#xff09;是一个用于安全漏洞测试的 PHP/MySQL 网络应用&#xff0c;旨在为安全专业人士提供一个合法的环境&#xff0c;以测试他们的技能和工具&#xff0c;同时帮助 Web 开发者更好地理解 …

大棚分割数据集,40765对影像,16.9g数据量,0.8米高分二,纯手工标注(arcgis标注)的大规模农业大棚分割数据集。

数据集名称&#xff1a; &#xff09;“Greenhouse Segmentation Dataset (GSD)” 数据集规模&#xff1a; 包含40,765对用于大棚分割的影像数据&#xff0c;每对影像包括一张原始图像和相应的分割标签图。 数据量&#xff1a; 总数据量约为16.9GB&#xff0c;适合存储在现…

【数据仓库】数据仓库常见的数据模型——维度模型

文章部分图参考自&#xff1a;多维数据模型各种类型&#xff08;星型、雪花、星座、交叉连接&#xff09; - 知乎 (zhihu.com) 文章部分文字canla一篇文章搞懂数据仓库&#xff1a;四种常见数据模型&#xff08;维度模型、范式模型等&#xff09;-腾讯云开发者社区-腾讯云 (ten…

Android插件化(四)基础之Hook

Android插件化(四)基础之Hook 1、寻找Hook点的原则 Android中主要是依靠分析系统源码类来做到的&#xff0c;首先我们得找到被Hook的对象&#xff0c;我称之为Hook点&#xff1b;什么样的对象比较好Hook呢&#xff1f;一般来说&#xff0c;静态变量和单例变量是相对不容易改变…

第14章 存储器的保护

第14章 存储器的保护 该章主要介绍了GDT、代码段、数据段、栈段等的访问保护机制。 存储器的保护功能可以禁止程序的非法内存访问。利用存储器的保护功能&#xff0c;也可以实现一些有价值的功能&#xff0c;比如虚拟内存管理。 代码清单14-1 该章节的代码主要实现的功能就…

详解Transformer位置编码Positional Encoding

提到 Transformer&#xff0c;大家就会联想到位置编码、注意力机制、编码器-解码器结构&#xff0c;本系列教程将探索 Transformer 的不同模块在故障诊断等信号分类任务中扮演什么样角色&#xff0c;到底哪些模块起作用&#xff1f; 前言 本期基于凯斯西储大学&#xff08;CWR…

微搭低代码实战:构建个性化点餐小程序

目录 前言书籍目录第1章&#xff1a;从零开始&#xff0c;认识微搭低代码平台第2章&#xff1a;用户认证与登录体验优化第3章&#xff1a;点餐小程序功能实现&#xff0c;包括创建应用、页面布局、组件使用等。第4章&#xff1a;变量定义与初始化&#xff0c;讲解低代码开发中变…

Docker部署Joplin Server教程

Joplin Server 是 Joplin 应用的后端服务,提供笔记和待办事项的同步功能。它允许用户在不同设备之间同步笔记,同时支持多用户和协作功能。Joplin Server使用现代技术栈,数据库使用的是 PostgreSQL 。 主要功能 同步:在桌面、移动设备和网页应用之间同步笔记。多用户支持:允…

Qt QSerialPort数据发送和接收DataComm

文章目录 Qt QSerialPort数据发送和接收DataComm2.添加 Qt Serial Port 模块3.实例源码 Qt QSerialPort数据发送和接收DataComm Qt 框架的Qt Serial Port 模块提供了访问串口的基本功能&#xff0c;包括串口通信参数配置和数据读写&#xff0c;使用 Qt Serial Port 模块就可以…

在react中 使用redux

1.安装redux npm install reduxjs/toolkit react-redux 2.创建切片模块化数据 在Src目录下创建store目录&#xff0c;创建moude目录 创建tab.js import { createSlice } from reduxjs/toolkit; const tabSlice createSlice({name: tab,initialState: {Collapse: false,},re…

C# WinForm 中 DataGridView 实现单元格cell 能进编辑状态但是不能修改单元格的效果

在Windows Forms&#xff08;WinForms&#xff09;开发中&#xff0c;DataGridView 控件是一个功能强大的组件&#xff0c; 用于显示和管理表格数据。无论是展示大量数据&#xff0c;还是实现交互式的数据操作&#xff0c; DataGridView 都能提供多样的功能支持&#xff0c;比如…

CLUSTERDOWN Hash slot not served问题复现

1、一主两从 172.31.4.18:6381> cluster nodes f5e774bd5cd8f5bcba53f1297015f3245dd3f18c 172.31.4.20:638316383 master - 0 1726278342891 10 connected 5461-10922 9a79febbfb1d7a8f7a6ba3fb11e86b0f122f71e7 172.31.4.21:638616386 slave 401730ba6e1c2cd8b60243990f0…

C++设计模式(更新中)

文章目录 1、创建型模式1.1 简单工厂&#xff08;Simple Factory&#xff09;&#xff08;1&#xff09;示例&#xff08;2&#xff09;总结 1.2 工厂方法&#xff08;Factory Method&#xff09;&#xff08;1&#xff09;示例&#xff08;2&#xff09;总结 1.3 抽象工厂&…

PL/SQL程序设计入门

PL/SQL程序设计 PL/SQL起步鼻祖&#xff1a;hello World语法分析声明部分举例 应用举例 PL/SQL 起步鼻祖&#xff1a;hello World 先举个例子&#xff0c;用PL/SQL打印输出hello world declarev_string varchar2(20); beginv_string:hello world;dbms_output.put_line(v_str…