深度优先搜索(DFS)和广度优先搜索(BFS)

1.深度优先搜索

深度优先搜索是一种在开发爬虫早期使用较多的方法。它的目的是要达到被搜索结构的叶结点(即那些不包含任何超链的HTML文件) 。在一个HTML文件中,当一个超链被选择后,被链接的HTML文件将执行深度优先搜索,即在搜索其余的超链结果之前必须先完整地搜索单独的一条链。深度优先搜索沿着HTML文件上的超链走到不能再深入为止,然后返回到某一个HTML文件,再继续选择该HTML文件中的其他超链。当不再有其他超链可选择时,说明搜索已经结束。

深度优先搜索属于图算法的一种,是一个针对图和树的遍历算法,英文缩写为DFS即Depth First Search。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的相应拓扑排序表,利用拓扑排序表可以方便的解决很多相关的图论问题,如最大路径问题等等。一般用堆数据结构来辅助实现DFS算法。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次。
(1)对于下面的树而言,DFS方法首先从根节点1开始,其搜索节点顺序是1,2,3,4,5,6,7,8(假定左分枝和右分枝中优先选择左分枝)。
在这里插入图片描述(2)从stack中访问栈顶的点;
在这里插入图片描述
(3)找出与此点邻接的且尚未遍历的点,进行标记,然后放入stack中,依次进行;
在这里插入图片描述(4)如果此点没有尚未遍历的邻接点,则将此点从stack中弹出,再按照(3)依次进行;
在这里插入图片描述
在这里插入图片描述
(5)直到遍历完整个树,stack里的元素都将弹出,最后栈为空,DFS遍历完成。
在这里插入图片描述
在这里插入图片描述
举例说明之二:下图是一个无向图,如果我们从A点发起深度优先搜索(以下的访问次序并不是唯一的,第二个点既可以是B也可以是C,D),则我们可能得到如下的一个访问过程:A->B->E(没有路了!回溯到A)->C->F->H->G->D(没有路,最终回溯到A,A也没有未访问的相邻节点,本次搜索结束).简要说明深度优先搜索的特点:每次深度优先搜索的结果必然是图的一个连通分量.深度优先搜索可以从多点发起.如果将每个节点在深度优先搜索过程中的"结束时间"排序(具体做法是创建一个list,然后在每个节点的相邻节点都已被访问的情况下,将该节点加入list结尾,然后逆转整个链表),则我们可以得到所谓的"拓扑排序",即topological sort

在这里插入图片描述

2.广度优先搜索

广度优先搜索(也称宽度优先搜索,缩写BFS,以下采用广度来描述)是连通图的一种遍历算法这一算法也是很多重要的图的算法的原型。Dijkstra单源最短路径算法和Prim最小生成树算法都采用了和宽度优先搜索类似的思想。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。基本过程,BFS是从根节点开始,沿着树(图)的宽度遍历树(图)的节点。如果所有节点均被访问,则算法中止。一般用队列数据结构来辅助实现BFS算法。

基本步奏

(1)给出一连通图,如图,初始化全是白色(未访问);
在这里插入图片描述
(2)搜索起点V1(灰色);
在这里插入图片描述
(3)已搜索V1(黑色),即将搜索V2,V3,V4(标灰);
在这里插入图片描述(4)对V2,V3,V4重复以上操作;
在这里插入图片描述
(5)直到终点V7被染灰,终止;
在这里插入图片描述
(6)最短路径为V1,V4,V7.

举例说明之二:这个例子比较有意思。假设你经营着一个芒果农场,需要寻找芒果销售商,以便将芒果卖给他。在Facebook,你与芒果销售商有联系吗?为此,你可在朋友中查找。
在这里插入图片描述
这种查找很简单。首先,创建一个朋友名单。
在这里插入图片描述
然后,依次检查名单中的每个人,看看他是否是芒果销售商。
在这里插入图片描述
假设你没有朋友是芒果销售商,那么你就必须在朋友的朋友中查找。
在这里插入图片描述
检查名单中的每个人时,你都将其朋友加入名单。
在这里插入图片描述这样一来,你不仅在朋友中查找,还在朋友的朋友中查找。别忘了,你的目标是在你的人际关系网中找到一位芒果销售商。因此,如果Alice不是芒果销售商,就将其朋友也加入到名单中。这意味着你将在她的朋友、朋友的朋友等中查找。使用这种算法将搜遍你的整个人际关系网,直到找到芒果销售商。这就是广度优先搜索算法。

广度优先搜索可回答两类问题。
第一类问题:从节点A出发,有前往节点B的路径吗?(在你的人际关系网中,有芒果销售商吗?)
第二类问题:从节点A出发,前往节点B的哪条路径最短?(哪个芒果销售商与你的关系最近?)
刚才你看到了如何回答第一类问题,下面来尝试回答第二类问题——谁是关系最近的芒果销售商。例如,朋友是一度关系,朋友的朋友是二度关系。
在这里插入图片描述
在你看来,一度关系胜过二度关系,二度关系胜过三度关系,以此类推。因此,你应先在一度关系中搜索,确定其中没有芒果销售商后,才在二度关系中搜索。广度优先搜索就是这样做的!在广度优先搜索的执行过程中,搜索范围从起点开始逐渐向外延伸,即先检查一度关系,再检查二度关系。顺便问一句:将先检查Claire还是Anuj呢?Claire是一度关系,而Anuj是二度关系,因
此将先检查Claire,后检查Anuj。

你也可以这样看,一度关系在二度关系之前加入查找名单。

你按顺序依次检查名单中的每个人,看看他是否是芒果销售商。这将先在一度关系中查找,再在二度关系中查找,因此找到的是关系最近的芒果销售商。广度优先搜索不仅查找从A到B的路径,而且找到的是最短的路径。
在这里插入图片描述
注意,只有按添加顺序查找时,才能实现这样的目的。换句话说,如果Claire先于Anuj加入名单,就需要先检查Claire,再检查Anuj。如果Claire和Anuj都是芒果销售商,而你先检查Anuj再检查Claire,结果将如何呢?找到的芒果销售商并非是与你关系最近的,因为Anuj是你朋友的朋友,而Claire是你的朋友。因此,你需要按添加顺序进行检查。有一个可实现这种目的的数据
结构,那就是队列(queue)。

参考:
https://www.jianshu.com/p/bff70b786bb6

https://baike.baidu.com/item/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2/5224976?fr=aladdin

https://blog.csdn.net/qq_37482202/article/details/89513877

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
下面是使用C语言实现深度优先搜索广度优先搜索的示例代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTEX_NUM 100 // 最大顶点数 // 图的邻接表存储结构 typedef struct ArcNode { int adjvex; // 该弧所指向的顶点的位置 struct ArcNode *next; // 指向下一条弧的指针 } ArcNode; typedef struct VNode { int data; // 顶点信息 ArcNode *first; // 指向第一条依附该顶点的弧的指针 } VNode; typedef struct Graph { VNode adjList[MAX_VERTEX_NUM]; // 邻接表 int vexNum, arcNum; // 图的顶点数和弧数 } Graph; // 初始化图 void InitGraph(Graph *G, int vexNum) { G->vexNum = vexNum; G->arcNum = 0; for (int i = 0; i < vexNum; i++) { G->adjList[i].data = i; G->adjList[i].first = NULL; } } // 添加弧 void AddArc(Graph *G, int from, int to) { ArcNode *arc = (ArcNode*)malloc(sizeof(ArcNode)); arc->adjvex = to; arc->next = G->adjList[from].first; G->adjList[from].first = arc; G->arcNum++; } // 深度优先搜索 void DFS(Graph *G, int v, int visited[]) { visited[v] = 1; printf("%d ", v); ArcNode *arc = G->adjList[v].first; while (arc != NULL) { int w = arc->adjvex; if (visited[w] == 0) { DFS(G, w, visited); } arc = arc->next; } } // 广度优先搜索 void BFS(Graph *G, int v, int visited[]) { int queue[MAX_VERTEX_NUM]; int front = 0, rear = 0; visited[v] = 1; printf("%d ", v); queue[rear++] = v; while (front < rear) { int w = queue[front++]; ArcNode *arc = G->adjList[w].first; while (arc != NULL) { int u = arc->adjvex; if (visited[u] == 0) { visited[u] = 1; printf("%d ", u); queue[rear++] = u; } arc = arc->next; } } } int main() { Graph G; int vexNum = 5; InitGraph(&G, vexNum); // 添加弧 AddArc(&G, 0, 1); AddArc(&G, 0, 2); AddArc(&G, 1, 3); AddArc(&G, 1, 4); // 深度优先搜索 int visited[MAX_VERTEX_NUM] = {0}; printf("DFS: "); DFS(&G, 0, visited); printf("\n"); // 广度优先搜索 for (int i = 0; i < vexNum; i++) { visited[i] = 0; } printf("BFS: "); BFS(&G, 0, visited); printf("\n"); return 0; } ``` 在这个示例代码中,我们使用邻接表来存储图,其中`VNode`表示顶点,`ArcNode`表示弧。`InitGraph`函数用于初始化图,`AddArc`函数用于添加弧。`DFS`函数和`BFS`函数分别表示深度优先搜索广度优先搜索。在这个示例代码中,我们使用递归来实现深度优先搜索,使用队列来实现广度优先搜索。最后,我们通过调用`DFS`函数和`BFS`函数来进行搜索。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一叶执念

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

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

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

打赏作者

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

抵扣说明:

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

余额充值