当前课程知识点:数据结构(上) > 第六章 图 > (c)广度优先搜索 > 06C-2 策略
所谓的广度优先遍历过程
可以大致描述为如下一段自然语言
具体来说 如果指定的起点是顶点s
那么这种搜索将首先访问s
在这个图中 我们通过将s染黑
表示它已经接受了访问
接下来我们需要访问
S所有尚未访问的邻接顶点
从这个图中来看
如果s具有若干个邻居
就需要逐一枚举
并且访问这些邻居
在这里由s通往它的那些
刚被访问的邻居的边都被加粗
这暗示着这些边都已经被我们的
算法所采纳和保留
这些边都是非常重要的
它们携带了整个遍历过程中
所发现的一些信息
我们很快就会看到
这些边将构成原图的一个
极大的无环子图
通常情况下是一棵树
或者是一个森林
反过来 在原图中
还会有一些边
我们并不采纳
比如在此时所有这些
刚被访问的节点之间
有可能也有连边
但是在经过广度优先遍历之后
它们将不再保留 而是被舍弃掉
接下来我们的关注点是
刚被访问的这些新发现的节点
我们将继续去枚举出
它们各自的所有邻接顶点
并且检查它们的状态
如果这些顶点中
仍有尚未访问者
就轮到对它们进行访问了
在这个图中 我们不妨
将这些新的顶点
画在图中的外围
也就是说 我们接下来将通过
刚刚被访问过的那些顶点
通往它们的边找到它们
同样地 在这些边中
也有一部分被我们保留下来
而另外一些则按照同样的原理
不予保留
再一次地 在新发现的这些顶点之间
也有可能连有某些边
比如说这些
而且这些边也同样地不会被
广度优先遍历所采纳
因此它们也没有加粗
好了 相对于这些
新近发现的顶点
在图中也就是这些
居于最外围的顶点
我们将再一次地去枚举出
它们所对应的邻居们
在图中 我们依然不妨
以更外围的一些顶点来示意
那么接下来也轮到
这些新发现的顶点
接受访问了
具体来说 我们也需要保留
若干由原先的顶点
通往新近访问这些顶点的边
而且同样地 尽管在这些顶点之间
也可能连有不同的边
我们也依然不予采纳
好 这个算法将不断地如此迭代反复
直到所有的顶点都接受了访问
仍以这幅图为例 我们可以看到
所谓广度优先搜索
的确是一种遍历
它会按照我们刚才
所介绍的那种策略
确定不同顶点接受访问的次序
并且按照这种次序
对各顶点逐个地访问
而整个搜索过程的最终产物或成果
不过是选自原图的一系列边
也就是这里加粗的这些边
而原图中其余的边
也就是这里用淡色细线条表示的边
都将被忽略
而不予进一步考虑
可以通过这个图看出
这里的取舍原则
也就是说 这里按照与起点s的距离
将所有的顶点划分为
若干个等价类
在这个图中 也就是一个套一个的环路
就像某些城市一样
可能有一环二环三环
以及诸如此类地 n环
那么在同一等价类内部
各顶点的边
都不会被采纳
而只有连接于相邻等价类之间的
某些边才会被采纳
请注意 同样是连接
相邻等价类顶点的边
未必都会被采纳
比如说这条 这条 这条 这条
以及这条 这条 这条和这条
而反过来 我们可以注意到
所有被保留下来
并且采纳的这些边
将足以把所有的顶点
连接起来
构成一个连通图
同时它们之间也因为刚才的规则
而不致于造成环路
也就是说 它是一个
极大的无环图
我们讲过 这就是一棵树
没错 它就是一棵树
因为这棵树中涵盖了
原图的所有的顶点
所以我们也称之为支撑树
Spanning Tree
另外 既然这样一个遍历过程
可以将所有的顶点划分为一个
一个又一个等价类
而且这些等价类
按照到起点s的距离
是逐次单调变化的
因此它与我们此前所介绍的
树的层次遍历
有异曲同工之妙
是的 对于图的特例
也就是树而言
这样一个遍历过程
其实就是不折不扣的层次遍历
所以反过来 我们也可以认为
所谓图的广度优先遍历
实际上就等同于
树的层次遍历
后者可以认为是前者的一个特例
而反过来 前者也是后者的推广
好了 那么这样一种
用自然语言描述的遍历过程
如何严格地描述为算法
并且实现为具体的代码呢?
-选课之前
--写在选课之前
--宣传片
-考核方式
--考核方式
-OJ系统说明
--关于OJ
--1-注册与登录
--2-界面与选课
--3-提交测试
-关于课程教材与讲义
--课程教材与讲义
-关于讨论区
--关于讨论区
-微信平台
--html
-PA晋级申请
--PA晋级
-(a)计算
--演示
--(a)计算--作业
-(b)计算模型
-(b)计算模型--作业
-(c)大O记号
-(c)大O记号--作业
-(d)算法分析
-(d)算法分析--作业
-(e)迭代与递归
-(e)迭代与递归--作业
-(xc)动态规划
-- 演示
-(xc)动态规划--作业
-本章测验--作业
-(a)接口与实现
--02A-5 复制
-(a)接口与实现--作业
-(b)可扩充向量
-(b)可扩充向量--作业
-(c)无序向量
--02C-1 概述
--02C-3 插入
--02C-6 查找
--02C-8 遍历
-(c)无序向量--作业
-(d1)有序向量:唯一化
-(d1)有序向量:唯一化--作业
-(d2)有序向量:二分查找
-(d2)有序向量:二分查找--作业
-(d3)有序向量:Fibonacci查找
-(d3)有序向量:Fibonacci查找--作业
-(d4)有序向量:二分查找(改进)
-(d4)有序向量:二分查找(改进)--作业
-(d5)有序向量:插值查找
-第二章 向量(下)--(d5)有序向量:插值查找
-(e)起泡排序
--02E-2 改进
--02E-3 反例
-(e)起泡排序--作业
-(f)归并排序
-(f)归并排序--作业
-本章测验--作业
-(a)接口与实现
--03A-4 实现
-(a)接口与实现--作业
-(b)无序列表
--03B-2 查找
-(b)无序列表--作业
-(c)有序列表
--03C-3 查找
-(c)有序列表--作业
-(d)选择排序
--03D-1 构思
--03D-2 实例
--03D-3 实现
--03D-4 推敲
--03D-6 性能
-(d)选择排序--作业
-(e)插入排序
--03E-1 经验
--03E-2 构思
--03E-3 对比
--03E-4 实例
--03E-5 实现
-(e)插入排序--作业
-(xd)习题辅导:LightHouse
-本章测验--作业
- (a)栈接口与实现
--04A-1 栈
--04A-2 实例
--04A-3 实现
- (a)栈接口与实现--作业
-(c1)栈应用:进制转换
-第四章 栈与队列--(c1)栈应用:进制转换
-(c2)栈应用:括号匹配
-(c2)栈应用:括号匹配--作业
-(c3)栈应用:栈混洗
-第四章 栈与队列--(c3)栈应用:栈混洗
-(c4)栈应用:中缀表达式求值
-(c4)栈应用:中缀表达式求值--作业
-(c5)栈应用:逆波兰表达式
-第四章 栈与队列--(c5)栈应用:逆波兰表达式
-(d)队列接口与实现
--04D-1 接口
--04D-2 实例
--04D-3 实现
-第四章 栈与队列--本章测验
-(a)树
--05A-1 动机
--05A-2 应用
-(a)树--作业
-(b)树的表示
--05B-2 父亲
--05B-3 孩子
-第五章 二叉树--(b)树的表示
-(c)二叉树
-(c)二叉树--作业
-(d)二叉树实现
-(d)二叉树实现--作业
-(e1)先序遍历
-(e1)先序遍历--作业
-(e2)中序遍历
-第五章 二叉树--(e2)中序遍历
-(e4)层次遍历
-第五章 二叉树--(e4)层次遍历
-(e5)重构
-(e5)重构--作业
-本章测验--作业
-(a)概述
-(a)概述--作业
-(b1)邻接矩阵
-(b1)邻接矩阵--作业
-(c)广度优先搜索
--06C-2 策略
--06C-3 实现
--06C-5 实例
-(c)广度优先搜索--作业
-(d)深度优先搜索
--06D-1 算法
--06D-2 框架
--06D-3 细节
-(d)深度优先搜索--作业
-第六章 图--本章测验