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

news2025/6/7 23:21:36

目录

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开始进行DFS

    return 0;
}
 

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

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

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

相关文章

【JDK 8-函数式编程】4.3 Consumer

一、Consumer 接口 二、使用 Stage 1: 创建方法&#xff0c;实现 Consumer 接口 Stage 2: 调用方法 Stage 3: 执行结果 三、List 的 foreach 执行结果 一、Consumer 接口 消费型接口 : 将T作为输入&#xff0c;无返回值 调用方法 : void accept(T t); 用途 : 因为没有出…

代码随想录算法训练营第23期day1|704. 二分查找、27. 移除元素

目录 一、&#xff08;leetcode 704&#xff09;二分查找 1&#xff09;左闭右开 2&#xff09;左闭右闭 二、&#xff08;leetcode 27&#xff09;移除元素 1&#xff09;暴力解法 2&#xff09;双指针法 快慢指针法 双向指针 数组是存放在连续内存空间上的相同类型数…

HTML5编写旅游网页

网页样例&#xff1a;&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title…

【Java 基础篇】Java线程同步:Lock接口详解

在多线程编程中&#xff0c;线程同步是一个重要的话题。为了确保多个线程可以正确地协同工作&#xff0c;Java提供了多种线程同步机制。其中&#xff0c;Lock接口是一种强大而灵活的线程同步机制&#xff0c;它提供了比传统的synchronized关键字更多的控制和功能。本文将详细介…

mac安装chromedriver驱动详细步骤

1.查看浏览器版本 2.下载驱动 3.安装驱动 4.MacOS无法打开“chromedriver”&#xff0c;因为无法验证开发者 1.查看浏览器版本 在这里插入图片描述 2.下载驱动 下载驱动地址&#xff1a;链接: http://chromedriver.storage.googleapis.com/index.html. 下载和浏览器版本一致的…

图解直接映射(Direct mapped)、全相联(Fully-associative)和组相联(Set-associative)cache缓存基本原理

图解直接映射&#xff08;Direct mapped&#xff09;、全相联&#xff08;Fully-associative&#xff09;和组相联&#xff08;Set-associative&#xff09;cache 一&#xff0c;直接映射缓存&#xff08;Direct mapped caches&#xff09;1.1 直接映射示例1.2 直接映射原理1.3…

人类认知的贝叶斯与机器的贝叶斯

贝叶斯原理是一种基于概率的分析方法&#xff0c;可以用来估计一个事件发生的概率。在人类认知和机器学习领域中&#xff0c;都有对应的贝叶斯原理。 人类认知的贝叶斯原理&#xff1a; 在人类认知研究中&#xff0c;贝叶斯原理被认为是一种重要的思维方式。人类的认知过程通常…

算法、数据结构、计算机系统、数据库MYSQL、概率论、数学实验MATLAB、数学建模、马原、英语、杂项、QT项目

算法 冒号表达式 &#xff08;condition&#xff09;&#xff1f;x&#xff1a;y 可以三个条件 以此类推 &#xff08;condition1&#xff09;&#xff1f;x&#xff1a;&#xff08;condition2&#xff09;&#xff1f;y&#xff1a;z 判断三角形最简单的办法 bool canFormTr…

使用 K 均值聚类进行颜色分割

介绍 颜色分割是计算机视觉中使用的一种技术,用于根据颜色识别和区分图像中的不同对象或区域。聚类算法可以自动将相似的颜色分组在一起,而不需要为每种颜色指定阈值。当处理具有大范围颜色的图像时,或者当事先不知道确切的阈值时,这非常有用。 在本教程中,我们将探讨如何…

修炼离线:(三)sqoop插入hbase 报错权限问题

一&#xff1a;报错现象。 二&#xff1a;解决方式。 方法一&#xff1a;修改文件所有者。 切换hadoop用户&#xff1a;export HADOOP_USER_NAMEhdfs hadoop fs -chown -R root:root /方法二&#xff1a;修改权限 切换hadoop用户&#xff1a;export HADOOP_USER_NAMEhdfs ha…

现今主流物联网无线通信技术分类详解

无线技术正在迅速发展&#xff0c;并在人们的生活中发挥越来越大的作用。 而随着无线应用的增长&#xff0c;各种技术和设备也会越来越多&#xff0c;也越来越依赖于无线通信技术。 本文盘点下物联网中无线通信主要的技术。 一、无线通信技术的几大主流分类 1.美国通信委员会…

Fork() 函数:“父” 与 “子” 进程的交互(进程的创建)

阅读导航 前言一、fork函数初识1. 基本概念2. fork函数返回值 二、fork函数的写时拷贝三、总结温馨提示 前言 前面我们讲了C语言的基础知识&#xff0c;也了解了一些数据结构&#xff0c;并且讲了有关C的一些知识&#xff0c;也学习了一些Linux的基本操作&#xff0c;也了解并…

CDN内容分发系统

CDN 分发系统的架构。CDN 系统的缓存&#xff0c;也是一层一层的&#xff0c;能不访问后端真正的源&#xff0c;就不打扰它。 在没有 CDN 的情况下&#xff0c;用户向浏览器输入 www.web.com 这个域名&#xff0c;客户端访问本地 DNS 服务器的时候&#xff0c;如果本地 DNS 服务…

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

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

HiEV独家 | 接棒余承东,华为光产品线总裁靳玉志出任车BU CEO

作者 | 德新 编辑 | 王博 HiEV从多个信息源获悉&#xff0c;华为光产品线总裁靳玉志已于近期接任智能汽车解决方案BU CEO一职&#xff0c;而余承东担任智能汽车解决方案BU&#xff08;以下简称「车BU」&#xff09;董事长一职。 华为光产品线又称华为光传输与接入产品线&#…

基于Uniapp+SpringBoot+Vue的电影交流平台小程序设计与实现(源码+lw+部署文档+讲解等)

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

flink集群与资源@k8s源码分析-集群

0 介绍 本文是flink集群与资源@k8s源码分析系列的第二篇-集群 1 场景 下面详细分析各用例 2 启动k8s集群 k8s集群支持session和application模式,job模式将会被废弃,本文分析session模式集群 Configuration作为配置容器,几乎所有的构建需要从配置类获取配置项,这里不显示…

CSS浮动、定位

三种网页布局方式&#xff1a;普通流、浮动、定位 普通流&#xff1a;浏览器默认方式&#xff0c;块元素从上到下排序&#xff0c;行内元素从左到右排序&#xff08;碰到父元素的边界会自动换行&#xff09; 浮动 让一行内容纳多个盒子 核心&#xff1a;脱离普通流的控制 fl…

莱佛士设计学院 | 服装设计毕业作品欣赏(一)

这期给大家介绍了我们莱佛士学生suyao的服装设计毕业作品&#xff08;毕业设计研讨与创作课题&#xff09;——自我认同。 相信很多朋友都有看过《千与千寻》&#xff0c;这部电影以上世纪90年代日本泡沫经济时代为背景&#xff0c;千寻和她的父母误入了诡异世界后&#xff0c;…

华为数通方向HCIP-DataCom H12-831题库(单选题:81-100)

第81题 关于结构化的网络故障排除流程中的确认故障阶段的描述,正确的是? A、应关注如何更好的解决故障而不论该故障是否属于自己的负责范围。 B、应重视用户的意见,以用户的判断为依据来判断故障问题 C、应使影响最小化,尽量不让其他人知道网络出现了故障。 D、应确认排障…