DFS和BFS都是图的搜素算法
DFS:深度优先搜索,存放候补节点的数据结构是栈(先进后出)
BFS:广度优先搜索,存放候补节点的数据结构是队列(先进先出)
0. 分析
- 我们将顶点
1
作为搜索的起点。 - 以广度优先搜索进行分析:
- 1、先寻找
1
的邻接节点并对其进行搜索,找到2
、3
为1
的邻接节点(候补节点),因为BFS
是对距离近的顶点(直接相连的顶点)进行搜索,那么思考一下我们需要用什么数据结构存放顶点1
的邻接节点2
、3
呢?对,答案是使用队列
来存放。 - 2、我们对
1
进行搜索完毕,并将其的邻接节点2
、3
存放队列中,之后我们将从队列中拿出我们即将要搜索的下一个顶点,因为队列是先进先出,所以2
出队,对2
进行搜索,并将其邻接节点1
、3
、4
放入队列中。 - 3、当前队列元素为
3
、1
、3
、4
,取出队首元素3
对其进行搜索,并将其邻接节点1
、2
、4
、5
放入队列中。 - 4、注意:当前队列元素为
1
、3
、4
、1
、2
、4
、5
,取出队首元素1
对其进行搜索???1
不是我们的搜索起点么,怎么又重新对1
进行搜索?
这是因为我们并没有对已经搜索过的顶点和未被搜索过的顶点进行区分,我们可以为每一个顶点加上一个黑色标记,被搜索过的顶点我们将标记颜色改为白色,这样我们就可以区分出哪些顶点是被搜索过的,哪些是未被搜索过的。(这里我们使用标记f
布尔值来区分,已搜索:true,未搜索:false)
那1
,2
,3
的f
都为true
,其余顶点的f
为false
。 - 重新执行第4步搜索:当前队列元素为
1-true
、3-true
、4-false
、1-true
、2-true
、4-false
、5-true
,我们弹出1
,3
发现已被搜索过,继续弹出队首元素4
,其未被搜索,我们对4
进行搜索并将其f
=true
,将其邻接节点2
,3
放入队尾。 - 5、当前队列元素为
1-true
、2-true
、3-true
、5-false
、2-true
、3-true
,依次弹出被搜索过的队首元素1
、2
、3
,直到5
,对其进行搜索,并将其邻接节点3
放入队尾。 - 6、当前队列元素为
2-true
,3-true
,3-true
,依次弹出队首元素2
、3
、3
发现全部被搜索过,此时队列为空,搜索结束。
- 1、先寻找
感觉怎么样?BFS
你已经学会了。也并没有什么难度吧。
那我们总结一下BFS
吧:
- 存放BFS顶点的数据结构:
队列
- 搜索的结束条件:
队列为空
- 怎么区分顶点是否被搜索过:
对顶点加上一个标记,通过对标记的判断来区分
BFS
结束,DFS
学起来还会很难么?自己画个图尝试一下吧~
1. 广度优先搜索
代码实现:
public static <T> void bfs(Vertex<T> vertex) {
// 创建队列,用来作为临时存储顶点的空间
ArrayBlockingQueue<Vertex<T>> queue = new ArrayBlockingQueue<Vertex<T>>(8);
// 将顶点存到队列中
queue.add(vertex);
// 如果队列不为空,就进行搜索
while (!queue.isEmpty()) {
// 让队列中第一个顶点出队
Vertex<T> e = queue.poll();
// 如果该顶点没有被访问过就进行搜索
if (!e.isVisited){
System.out.print(e.data+" -> ");
e.isVisited=true;
// 如果该顶点有邻接节点,就将邻接节点全部放入队列中
if (e.neighList!=null){
queue.addAll(e.neighList);
}
}
}
}
2. 深度优先搜索
代码实现:
public static <T> void dfs(Vertex<T> vertex) {
// 创建一个栈用来当做临时存储空间
Stack<Vertex<T>> stack = new Stack<>();
// 将顶点压入栈中
stack.push(vertex);
// 如果栈不为空,就进行搜索
while (!stack.isEmpty()) {
// 将栈中第一个元素弹出
Vertex<T> e = stack.pop();
// 判断该顶点是否被访问过
if (!e.isVisited) {
System.out.print(e.data + " -> ");
// 标记已被访问
e.isVisited = true;
// 判断该顶点是否有邻接节点
if (e.neighList != null) {
// 将该顶点的所有邻接节点压入栈中
stack.addAll(e.neighList);
}
}
}
}
用到的顶点数据结构:
public static class Vertex<T> {
// 顶点的值
private T data;
// 顶点的邻接节点
private List<Vertex<T>> neighList;
// 判断是否被访问过的标记
private boolean isVisited;
public Vertex(T data) {
this.data = data;
}
}