算法是作用于具体数据结构之上的,深度优先搜索算法和广度优先搜索算法都是基于“图”这种数据结构的。
图上的搜索算法,最直接的理解就是,在图中找出从一个顶点出发,到另一个顶点的路径。
而深度和广度优先搜索就是图的众多搜索算法中最简单的,也是最“暴力”的搜索算法
代码实现
前提
代码中的图结构是利用邻链表实现的无权无向图。
import java.util.LinkedList;
import java.util.Queue;
public class Graph { //无向图
private int v; // 顶点的个数
private LinkedList<Integer> adj[]; // 邻接表
public Graph(int v) {
this.v = v;
adj = new LinkedList[v];
for (int i = 0; i < v; ++i) {
adj[i] = new LinkedList<>();
}
}
public void addEdge(int s, int t) { // 无向图一条边存两次
adj[s].add(t);
adj[t].add(s);
}
public void bfs(int s, int t) {
if (s == t) return;
boolean[] visited = new boolean[v]; //记录顶点是否被访问过,若被访问过则为true
visited[s]=true;
Queue<Integer> queue = new LinkedList<>(); //存储已经被访问、但相连的顶点还没有被访问的顶点。
queue.add(s);
int[] prev = new int[v]; //记录搜索路径,反向存储,prev[w]存储的是,顶点 w 是从哪个前驱顶点遍历过来的。
for (int i = 0; i < v; ++i) {
prev[i] = -1;
}
while (queue.size() != 0) { //一次循环将队列的队头顶点出队列
int w = queue.poll();
for (int i = 0; i < adj[w].size(); ++i) { //一次循环将已出队顶点相连的一个没有被访问过的节点入队列
int q = adj[w].get(i);
if (!visited[q]) { //若顶点没有被访问过,则记录下来顶点是从哪个前驱顶点遍历而来
prev[q] = w;
if (q == t) { //若已搜索到目的顶点,则打印输出路径
print(prev, s, t);
return;
}
visited[q] = true;
queue.add(q); //将顶点设为已访问状态,并且入队
}
}
}
}
private void print(int[] prev, int s, int t) { // 因为搜索路径是反向存储,递归打印s->t的路径
if (prev[t] != -1 && t != s) {
print(prev, s, prev[t]);
}
System.out.print(t + " ");
}
public static void main(String[] args) {
Graph graph = new Graph(8);
graph.addEdge(0,1);
graph.addEdge(0,3);
graph.addEdge(1,2);
graph.addEdge(1,4);
graph.addEdge(3,4);
graph.addEdge(2,5);
graph.addEdge(4,5);
graph.addEdge(4,6);
graph.addEdge(5,7);
graph.addEdge(6,7);
// Graph graph = new Graph(6);
// graph.addEdge(0,1);
// graph.addEdge(0,2);
// graph.addEdge(1,3);
// graph.addEdge(2,3);
// graph.addEdge(3,4);
// graph.addEdge(4,5);
// graph.bfs(0,5);
}
}