深度优先搜索遍历与广度优先搜索遍历

简介: 深度优先搜索遍历与广度优先搜索遍历

一.深度优先搜索遍历

1.深度优先遍历的方法

从图中一个未访问的顶点V开始,沿着一条路一直走到底,如果到达这条路尽头的节点 ,则回退到上一个节点,再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成。


以下面无向图为例,2为起点



(1)以2为起点访问1



(2)以1为起点,因为“1”和“2”之间的边已经走过,所以走3



(3) 同理,以3为起点访问5



(4)到5后,没有可访问的点,返回3,3也没有可访问的点,到1后,可访问之前没有访问过的4



(5)4访问6,至此,遍历完所有的点,DFS(深度优先搜索遍历):2->1->3->5->4->6



2.采用邻接矩阵表示图的深度优先搜索遍历

#define MAX_VERTEX_NUM 100
typedef struct {
    // 定义图的相关信息
    int vexnum;                    // 顶点数
    int arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];  // 邻接矩阵
    // 其他成员...
} AMSGraph;
bool visited[MAX_VERTEX_NUM];      // 记录顶点是否被访问过
void DFS(AMSGraph G, int v)
{
    cout << v;
    visited[v] = true;
    for (int w = 0; w < G.vexnum; w++) {
        if (G.arcs[v][w] == 1 && !visited[w]) {
            DFS(G, w);
        }
    }
}

http://t.csdn.cn/HmcOt


之前的一篇文章已经详细说明了邻接矩阵和邻接表的区别,这里同理


1.用邻接矩阵表示图,遍历图中每一个顶点都要从头扫描该顶点所在行,时间复杂度O()


2.用邻接表表示图,虽然有2e个表结点,但只需扫描e个结点即可完成遍历,加上访问n个头结点的时间,时间复杂度为O(n+e)


•稠密图适于在邻接矩阵上进行深度遍历;


•稀疏图适于在邻接表上进行深度遍历。


3.非连通图的遍历

左边的连通分量进行深度优先搜索遍历,再在b,g之中选择一个点进行深度优先搜索遍历


其中一种合理的顶点访问次序为:


a,c,h,d,f,k,e,b,g



二.广度优先搜索遍历

1.广度优先搜索遍历的方法

从某个顶点V出发,访问该顶点的所有邻接点V1,V2..VN,从邻接点V1,V2...VN出发,再访问他们各自的所有邻接点,重复上述步骤,直到所有的顶点都被访问过


以如下图为例,起点为V1



一层一层进行访问,广度优先搜索遍历的结果为:V1->C2->V3->V4->V5->V6->V7->V8


2.非连通图的广度遍历

与连通图类似,在b,g中任意选择一个点开始


合理的顶点访问次序为:a->c->d->e->f->h->k->b->g


3.广度优先搜索遍历的实现

广度优先搜索遍历的实现,与树的层次遍历很像,可以用队列进行实现(出队一个结点,将他的邻接结点入队)


以下动图来自爱编程的西瓜,方便大家理解遍历过程



4.按广度优先非递归遍历连通图

#include <iostream>
using namespace std;
const int MAX_SIZE = 100;  // 队列的最大容量
const int MAX_VERTICES = 100;  // 图的最大顶点数
struct Queue {
    int data[MAX_SIZE];
    int front;  // 队头指针
    int rear;  // 队尾指针
};
struct Graph {  // 定义图
    bool edges[MAX_VERTICES][MAX_VERTICES];  // 邻接矩阵
    int numVertices;  // 实际顶点数
};
void InitQueue(Queue& Q) {
    Q.front = 0;
    Q.rear = -1;
}
bool EnQueue(Queue& Q, int x) {
    if (Q.rear == MAX_SIZE - 1) {
        // 队列已满,无法插入
        return false;
    }
    Q.data[++Q.rear] = x;
    return true;
}
bool DeQueue(Queue& Q, int& x) {
    if (Q.front > Q.rear) {
        // 队列为空,无法出队
        return false;
    }
    x = Q.data[Q.front++];
    return true;
}
bool QueueEmpty(Queue& Q) {
    return Q.front > Q.rear;
}
// 找到顶点u的第一个邻接点并返回
int FirstAdjVex(Graph& G, int u) {
    for (int v = 0; v < G.numVertices; ++v) {
        if (G.edges[u][v]) {
            return v;
        }
    }
    return -1;  // 或者返回一个特殊的值表示找不到邻接点
}
// 找到图 G 中顶点 u 相对于顶点 w 的下一个邻接点并返回
int NextAdjVex(Graph& G, int u, int w) {
    for (int v = w + 1; v < G.numVertices; ++v) {
        if (G.edges[u][v]) {
            return v;
        }
    }
    return -1;  // 或者返回一个特殊的值表示找不到下一个邻接点
}
void BFS(Graph G, int v) {
    cout << v;
    bool visited[MAX_VERTICES] = { false };
    visited[v] = true;  // 访问第v个顶点
    Queue Q;
    InitQueue(Q);
    EnQueue(Q, v);  // v进队
    while (!QueueEmpty(Q)) {
        int u;
        DeQueue(Q, u);  // 队头元素出队并置为u
        for (int w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)) {
            if (!visited[w]) {  // w为u的尚未访问的邻接点
                cout << w;
                visited[w] = true;
                EnQueue(Q, w);  // w进队(将访问的每一个邻接点入队)
            }
        }
    }
}


广度优先搜索遍历算法的效率


1.如果使用邻接矩阵,则BFS对于每一个被访问到的顶点,都要循环检测矩阵中的整整一行,时间复杂度为O()


2.用邻接表来表示图,虽然有2e个表结点,但只需扫描e个结点即可完成遍历,加上访问n个头结点的实践,时间复杂度为O(n+e)


深度优先搜索遍历(DFS)与广度优先搜索遍历(BFS)算法的效率


1.空间复杂度相同,都是O(n)(借用了堆栈或队列)


2.时间复杂度只与存储结构(邻接矩阵【O()】或邻接表【O(n+e)】)有关,而与搜索路径无关


目录
相关文章
|
4月前
|
前端开发 算法
深度研究Agent架构解析:4种Agent架构介绍及实用Prompt模板
本文系统梳理了深度搜索Agent的主流架构演进:从基础的Planner-Only,到引入评估反馈的双模块设计,再到支持层次化分解的递归式ROMA方案。重点解析了问题拆解与终止判断两大核心挑战,并提供了实用的Prompt模板与优化策略,为构建高效搜索Agent提供清晰路径。
1872 10
深度研究Agent架构解析:4种Agent架构介绍及实用Prompt模板
|
机器学习/深度学习 人工智能 计算机视觉
带你读《深度学习与图像识别:原理与实践》之一:机器视觉在行业中的应用
这是一部从技术原理、算法和工程实践3个维度系统讲解图像识别的著作,由阿里巴巴达摩院算法专家、阿里巴巴技术发展专家、阿里巴巴数据架构师联合撰写。在知识点的选择上,本书广度和深度兼顾,既能让完全没有基础的读者迅速入门,又能让有基础的读者深入掌握图像识别的核心技术;在写作方式上,本书避开了复杂的数学公式及其推导,从问题的前因后果 、创造者的思考过程,利用简单的数学计算来做模型分析和讲解,通俗易懂。更重要的是,本书不仅仅是聚焦于技术,而是将重点放在了如何用技术解决实际的业务问题。
|
4月前
|
算法 NoSQL Java
拒绝服务雪崩!4种经典限流算法图文详解(附Java实战代码)
限流是保护系统的“保险丝”,防止突发流量导致服务雪崩。常见算法有:固定窗口(简单但有突刺)、滑动窗口(精准平滑)、漏桶(恒定处理速率)和令牌桶(允许突发,最常用)。单机限流可用计数器或Guava,分布式场景则依赖Redis实现全局控制。
901 9
|
前端开发 jenkins 测试技术
自动化测试介绍,为何 Apifox 是进行自动化测试的最佳工具
自动化测试利用专用软件执行测试用例,比手动测试更高效准确。Apifox是一款集API文档、调试与自动化测试于一体的工具,提供一体化解决方案,简化API变更管理。其强大的测试功能支持丰富的断言及测试场景组合,便于模拟真实业务流程。Apifox还提供详尽的测试报告与分析功能,有助于快速定位问题。此外,它能轻松集成到CI/CD流程中,并支持定时任务及多分支管理,极大提升了测试效率和团队协作。相较于其他工具,Apifox以其全面的功能和友好的界面脱颖而出。
|
12月前
|
人工智能 自然语言处理 API
推荐几个常用免费的文本转语音工具
本文推荐了几款免费的文本转语音工具,包括功能全面的AI易视频、支持多语言的Google TTS、操作便捷的Natural Reader、离线使用的Balabolka以及轻量级的Speech2Go。其中AI易视频特别适合小说转语音,可智能分配角色音色,打造广播剧般的听觉体验。这些工具各具特色,能满足不同场景需求,助力内容创作更高效。
3934 5
|
存储 机器学习/深度学习 人工智能
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
|
开发框架 Java 开发者
Spring Boot中的自动装配原理
Spring Boot中的自动装配原理
3824 1
|
开发框架 前端开发 C#
从零开始学 Blazor 创建 Web 应用,入门指南超详细!带你轻松开启精彩的开发之旅!
【8月更文挑战第31天】在互联网时代,Web应用开发愈发重要,Blazor作为新兴框架,允许使用C#和.NET技术构建交互式Web应用,提高开发效率与代码可维护性。本文将从零开始引导读者了解Blazor的基本概念,安装设置步骤,项目创建及运行方法。通过简单的示例介绍Blazor的基本结构,包括Pages、Shared等文件夹用途,以及Program.cs文件的功能。同时,还将演示如何创建Razor页面和组件,实现数据绑定与事件处理,帮助读者快速入门Blazor开发。
2205 0
|
SQL 容灾 数据库
分布式事务Seata
在分布式架构系统中,服务不止一个,一个完整的业务链路肯定也不止调用一个服务,此时每个服务都有自己的数据库增删改查,而每一个写操作对应一个本地事务。如果想要确保全部的业务状态一致,也就意味着需要所有的本地事务状态一致,这在我们之前的学习中肯定是不具备的,如何做到跨服务、跨数据源的事务一致性将是本章节的重点学习内容。
838 2
|
存储 机器学习/深度学习 算法
数据结构学习笔记——图的遍历算法(深度优先搜索和广度优先搜索)
数据结构学习笔记——图的遍历算法(深度优先搜索和广度优先搜索)
数据结构学习笔记——图的遍历算法(深度优先搜索和广度优先搜索)