广度优先搜索(Breadth First Search)

广度优先搜索简称BFS,是一种以“广度”为第一关键词的算法,当碰到岔道口时,总是优先考虑从该岔道口能直接到达的所有节点,以此类推,直到所有节点都被访问位置,类似于掉入水面的石子,激起的水波纹总是以石子掉落点为圆心向周围以圆的方式扩散开来。
BFS的运行方式类似于队列,所以,基本上所有的BFS题目大多都采用队列的形式来解决,例:对于当前模拟到的任意一个元素,将其按规定条件能访问到的每一个元素按访问次序入队,接着遵循以上的规律逐个处理队列内的元素,直到队列空为止,对队列的操作遵循模板如下:

#include<queue>
using namespace std;
void bfs(int temp){//这里的int型temp可以是任意类型,下面队列中存入的数据也可以是任意类型
    queue<int> q;
    q.push(temp);
    //这里可以存在不同的定义与操作
    while(!q.empty()){
        //取出队首元素top
        //访问队首元素top
        //将队首元素出队
        //将top的下一层结点中未曾入队的结点全部入队,并设置为已入队
    }
}

有一点需要特别关注的就是,一般BFS的题目里都会存在一个inq标记数组用来记录当前搜索到的元素是否已经入过队列,以上模板最后一行将top的下一层未曾入队的结点入队使用的判断就是这个bool型的inq => “in queue”数组,该数组初始化一般为false,当某个位置符合条件的时候,将其变更为true,该数组经常在一道题目的代码中会出现四次,第一次初始化该数组,第二次在judge函数判断当前节点是否入队的时候出现,第三次在while循环里当某个元素符合入队条件的时候将其入队时候出现(用来将该位置标记为true代表已经入过队)第四次出现在main函数里,在枚举所有位置的时候判断是否需要使用BFS函数,当然,这几次都不是必须,还是应该具题来讨论,但是对于大多数题目的基本套路来讲,以上的思路和模板还是应该记住的,总结一下,BFS的大多数题目遵循这样的流程:
结构体定义元素节点

  1. 定义需要输入的变量与常量并初始化inq与题目的样例输入数组以及增量数组等(不是必须)
  2. 定义bool 类型的判断函数judge为了未来在bfs函数的whule循环中使用
  3. 定义最重要的bfs函数,bfs函数内部遵循本笔记上方的模板代码
  4. 定义main函数

    总之,BFS永远是以广度为优先考虑项注重于搜索时按层搜索”地毯式“,而一般问题的答案,就是BFS搜索到某一最终目的地所使用的最短层数其次,在BFS中设置的inq数组含义是”当前枚举到的元素是否已入过队“而不是”当前元素是否已被访问“,因为如果标记为true的条件是是否已被访问,那么就会出现某个节点已经因为地毯式的搜索而已经在队列中存在,但是对于正常的遍历顺序来讲它还未被访问,就可能会出现在接下来的顺序遍历中再次将该元素二次入队,这样会导致计算量大大增加。
    最后注意一点:C++STL中的queue函数对于入队的push操作只是对其生成了一个该入队元素的副本,而不是传入了该元素的指针或者引用,所以对队列中的元素访问改变不会对初始的原本元素有任何改变,自然,改变原始元素也不会改变队列中的元素。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
/* * (有向)图的深度优先遍历算法模板 */ package dsa; public abstract class DFS extends GraphTraverse { //变量 protected static int clock = 0;//遍历过程中使用的计时钟 //构造方法 public DFS(Graph g) { super(g); } //深度优先遍历算法 protected Object traverse(Vertex v, Object info) {//从顶点v出发,做深度优先查找 if (UNDISCOVERED != v.getStatus()) return null;//跳过已访问过的顶点(针对非连通图) v.setDStamp(clock++); v.setStatus(DISCOVERED); visit(v, info);//访问当前顶点 for (Iterator it = v.outEdges(); it.hasNext();) {//检查与顶点v Edge e = (Edge)it.getNext();//通过边e = (v, u) Vertex u = (Vertex)e.getVPosInV(1).getElem();//相联的每一顶点u switch (u.getStatus()) {//根据u当前的不同状态,分别做相应处理 case UNDISCOVERED ://若u尚未被发现,则 e.setType(TREE);//e被归类为“树边” traverse(u, info);//从u出发,继续做深度优先查找 break; case DISCOVERED ://若u已经被发现,但对其访问尚未结束,则 e.setType(BACKWARD);//将e归类为“后向跨边” break; default ://VISITED,即对u的访问已经结束 if (u.getDStamp() < v.getDStamp())//若相对于v,u被发现得更早,则 e.setType(CROSS);//将e归类为“横跨边” else//否则 e.setType(FORWARD);//将e归类为“前向跨边” break; } }//至此,v的所有邻居都已访问结束,故 v.setFStamp(clock++); v.setStatus(VISITED);//将v标记为VISITED return null;//然后回溯 } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苯酸氨酰糖化物

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值